Implement Folder
diff --git a/src/fold.rs b/src/fold.rs
new file mode 100644
index 0000000..76c1948
--- /dev/null
+++ b/src/fold.rs
@@ -0,0 +1,943 @@
+// Adapted from libsyntax.
+
+//! A Folder represents an AST->AST fold; it accepts an AST piece,
+//! and returns a piece of the same type. 
+
+use super::*;
+
+/// AST->AST fold.
+///
+/// Each method of the Folder trait is a hook to be potentially overridden. Each
+/// method's default implementation recursively visits the substructure of the
+/// input via the `noop_fold` methods, which perform an "identity fold", that
+/// is, they return the same structure that they are given (for example the
+/// `fold_crate` method by default calls `fold::noop_fold_crate`).
+///
+/// If you want to ensure that your code handles every variant explicitly, you
+/// need to override each method and monitor future changes to `Folder` in case
+/// a new method with a new default implementation gets introduced.
+pub trait Folder: Sized {
+    // Any additions to this trait should happen in form
+    // of a call to a public `noop_*` function that only calls
+    // out to the folder again, not other `noop_*` functions.
+    //
+    // This is a necessary API workaround to the problem of not
+    // being able to call out to the super default method
+    // in an overridden default method.
+
+    fn fold_ident(&mut self, _ident: Ident) -> Ident {
+        noop_fold_ident(self, _ident)
+    }
+    fn fold_derive_input(&mut self, derive_input: DeriveInput) -> DeriveInput {
+        noop_fold_derive_input(self, derive_input)
+    }
+    fn fold_ty(&mut self, ty: Ty) -> Ty {
+        noop_fold_ty(self, ty)
+    }
+    fn fold_generics(&mut self, generics: Generics) -> Generics {
+        noop_fold_generics(self, generics)
+    }
+    fn fold_ty_param_bound(&mut self, bound: TyParamBound) -> TyParamBound {
+        noop_fold_ty_param_bound(self, bound)
+    }
+    fn fold_poly_trait_ref(&mut self, trait_ref: PolyTraitRef) -> PolyTraitRef {
+        noop_fold_poly_trait_ref(self, trait_ref)
+    }
+    fn fold_variant_data(&mut self, data: VariantData) -> VariantData {
+        noop_fold_variant_data(self, data)
+    }
+    fn fold_field(&mut self, field: Field) -> Field {
+        noop_fold_field(self, field)
+    }
+    fn fold_variant(&mut self, variant: Variant) -> Variant {
+        noop_fold_variant(self, variant)
+    }
+    fn fold_lifetime(&mut self, _lifetime: Lifetime) -> Lifetime {
+        noop_fold_lifetime(self, _lifetime)
+    }
+    fn fold_lifetime_def(&mut self, lifetime: LifetimeDef) -> LifetimeDef {
+        noop_fold_lifetime_def(self, lifetime)
+    }
+    fn fold_path(&mut self, path: Path) -> Path {
+        noop_fold_path(self, path)
+    }
+    fn fold_path_segment(&mut self, path_segment: PathSegment) -> PathSegment {
+        noop_fold_path_segment(self, path_segment)
+    }
+    fn fold_path_parameters(&mut self, path_parameters: PathParameters) -> PathParameters {
+        noop_fold_path_parameters(self, path_parameters)
+    }
+    fn fold_assoc_type_binding(&mut self, type_binding: TypeBinding) -> TypeBinding {
+        noop_fold_assoc_type_binding(self, type_binding)
+    }
+    fn fold_attribute(&mut self, _attr: Attribute) -> Attribute {
+        noop_fold_attribute(self, _attr)
+    }
+    fn fold_fn_ret_ty(&mut self, ret_ty: FunctionRetTy) -> FunctionRetTy {
+        noop_fold_fn_ret_ty(self, ret_ty)
+    }
+    fn fold_const_expr(&mut self, expr: ConstExpr) -> ConstExpr {
+        noop_fold_const_expr(self, expr)
+    }
+    fn fold_lit(&mut self, _lit: Lit) -> Lit {
+        noop_fold_lit(self, _lit)
+    }
+
+    fn fold_mac(&mut self, mac: Mac) -> Mac {
+        noop_fold_mac(self, mac)
+    }
+
+    #[cfg(feature = "full")]
+    fn fold_crate(&mut self, _crate: Crate) -> Crate {
+        noop_fold_crate(self, _crate)
+    }
+    #[cfg(feature = "full")]
+    fn fold_item(&mut self, item: Item) -> Item {
+        noop_fold_item(self, item)
+    }
+    #[cfg(feature = "full")]
+    fn fold_expr(&mut self, expr: Expr) -> Expr {
+        noop_fold_expr(self, expr)
+    }
+    #[cfg(feature = "full")]
+    fn fold_foreign_item(&mut self, foreign_item: ForeignItem) -> ForeignItem {
+        noop_fold_foreign_item(self, foreign_item)
+    }
+    #[cfg(feature = "full")]
+    fn fold_pat(&mut self, pat: Pat) -> Pat {
+        noop_fold_pat(self, pat)
+    }
+    #[cfg(feature = "full")]
+    fn fold_fn_decl(&mut self, fn_decl: FnDecl) -> FnDecl {
+        noop_fold_fn_decl(self, fn_decl)
+    }
+    #[cfg(feature = "full")]
+    fn fold_trait_item(&mut self, trait_item: TraitItem) -> TraitItem {
+        noop_fold_trait_item(self, trait_item)
+    }
+    #[cfg(feature = "full")]
+    fn fold_impl_item(&mut self, impl_item: ImplItem) -> ImplItem {
+        noop_fold_impl_item(self, impl_item)
+    }
+    #[cfg(feature = "full")]
+    fn fold_method_sig(&mut self, method_sig: MethodSig) -> MethodSig {
+        noop_fold_method_sig(self, method_sig)
+    }
+    #[cfg(feature = "full")]
+    fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
+        noop_fold_stmt(self, stmt)
+    }
+    #[cfg(feature = "full")]
+    fn fold_block(&mut self, block: Block) -> Block {
+        noop_fold_block(self, block)
+    }
+    #[cfg(feature = "full")]
+    fn fold_local(&mut self, local: Local) -> Local {
+        noop_fold_local(self, local)
+    }
+    #[cfg(feature = "full")]
+    fn fold_view_path(&mut self, view_path: ViewPath) -> ViewPath {
+        noop_fold_view_path(self, view_path)
+    }
+}
+
+trait LiftOnce<T, U> {
+    type Output;
+    fn lift<F>(self, f: F) -> Self::Output where F: FnOnce(T) -> U;
+}
+
+impl<T, U> LiftOnce<T, U> for Box<T> {
+    type Output = Box<U>;
+    fn lift<F>(self, f: F) -> Box<U>
+        where F: FnOnce(T) -> U
+    {
+        Box::new(f(*self))
+    }
+}
+
+trait LiftMut<T, U> {
+    type Output;
+    fn lift<F>(self, f: F) -> Self::Output where F: FnMut(T) -> U;
+}
+
+impl<T, U> LiftMut<T, U> for Vec<T> {
+    type Output = Vec<U>;
+    fn lift<F>(self, f: F) -> Vec<U>
+        where F: FnMut(T) -> U
+    {
+        self.into_iter().map(f).collect()
+    }
+}
+
+
+// -
+pub fn noop_fold_ident<F: Folder>(_: &mut F, _ident: Ident) -> Ident {
+    _ident
+}
+
+// -
+pub fn noop_fold_derive_input<F: Folder>(folder: &mut F,
+                                         DeriveInput{ ident,
+                                                      vis,
+                                                      attrs,
+                                                      generics,
+                                                      body }: DeriveInput) -> DeriveInput {
+    use self::Body::*;
+    DeriveInput {
+        ident: folder.fold_ident(ident),
+        vis: noop_fold_vis(folder, vis),
+        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+        generics: folder.fold_generics(generics),
+        body: match body {
+            Enum(variants) => {
+                Enum(variants.lift(move |v| folder.fold_variant(v)))
+            }
+            Struct(variant_data) => Struct(folder.fold_variant_data(variant_data)),
+        },
+    }
+}
+
+// -
+pub fn noop_fold_ty<F: Folder>(folder: &mut F, ty: Ty) -> Ty {
+    use self::Ty::*;
+    match ty {
+        Slice(inner) => Slice(inner.lift(|v| folder.fold_ty(v))),
+        Paren(inner) => Paren(inner.lift(|v| folder.fold_ty(v))),
+        Ptr(mutable_type) => {
+            let mutable_type_ = *mutable_type;
+            let MutTy { ty, mutability }: MutTy = mutable_type_;
+            Ptr(Box::new(MutTy {
+                ty: folder.fold_ty(ty),
+                mutability: mutability,
+            }))
+        }
+        Rptr(opt_lifetime, mutable_type) => {
+            let mutable_type_ = *mutable_type;
+            let MutTy { ty, mutability }: MutTy = mutable_type_;
+            Rptr(opt_lifetime.map(|l| folder.fold_lifetime(l)),
+                 Box::new(MutTy {
+                     ty: folder.fold_ty(ty),
+                     mutability: mutability,
+                 }))
+        }
+        Never => Never,
+        Infer => Infer,
+        Tup(tuple_element_types) => Tup(tuple_element_types.lift(|x| folder.fold_ty(x))),
+        BareFn(bare_fn) => {
+            let bf_ = *bare_fn;
+            let BareFnTy { unsafety, abi, lifetimes, inputs, output, variadic } = bf_;
+            BareFn(Box::new(BareFnTy {
+                unsafety: unsafety,
+                abi: abi,
+                lifetimes: lifetimes.lift(|l| folder.fold_lifetime_def(l)),
+                inputs: inputs.lift(|v| {
+                    BareFnArg {
+                        name: v.name.map(|n| folder.fold_ident(n)),
+                        ty: folder.fold_ty(v.ty),
+                    }
+                }),
+                output: folder.fold_fn_ret_ty(output),
+                variadic: variadic,
+            }))
+        }
+        Path(maybe_qself, path) => {
+            Path(maybe_qself.map(|v| noop_fold_qself(folder, v)),
+                 folder.fold_path(path))
+        }
+        Array(inner, len) => {
+            Array({
+                      inner.lift(|v| folder.fold_ty(v))
+                  },
+                  folder.fold_const_expr(len))
+        }
+        TraitObject(bounds) => TraitObject(bounds.lift(|v| folder.fold_ty_param_bound(v))),
+        ImplTrait(bounds) => ImplTrait(bounds.lift(|v| folder.fold_ty_param_bound(v))),
+        Mac(mac) => Mac(folder.fold_mac(mac)),
+    }
+}
+
+fn noop_fold_qself<F: Folder>(folder: &mut F, QSelf { ty, position }: QSelf) -> QSelf {
+    QSelf {
+        ty: Box::new(folder.fold_ty(*(ty))),
+        position: position,
+    }
+}
+
+// -
+pub fn noop_fold_generics<F: Folder>(folder: &mut F,
+                                     Generics { lifetimes, ty_params, where_clause }: Generics)
+                                     -> Generics {
+    use self::WherePredicate::*;
+    Generics {
+        lifetimes: lifetimes.lift(|l| folder.fold_lifetime_def(l)),
+        ty_params: ty_params.lift(|ty| {
+            TyParam {
+                attrs: ty.attrs.lift(|a| folder.fold_attribute(a)),
+                ident: folder.fold_ident(ty.ident),
+                bounds: ty.bounds
+                    .lift(|ty_pb| folder.fold_ty_param_bound(ty_pb)),
+                default: ty.default.map(|v| folder.fold_ty(v)),
+            }
+        }),
+        where_clause: WhereClause {
+            predicates: where_clause.predicates
+                .lift(|p| match p {
+                    BoundPredicate(bound_predicate) => {
+                        BoundPredicate(WhereBoundPredicate {
+                            bound_lifetimes: bound_predicate.bound_lifetimes
+                                .lift(|l| folder.fold_lifetime_def(l)),
+                            bounded_ty: folder.fold_ty(bound_predicate.bounded_ty),
+                            bounds: bound_predicate.bounds
+                                .lift(|ty_pb| folder.fold_ty_param_bound(ty_pb)),
+                        })
+                    }
+                    RegionPredicate(region_predicate) => {
+                        RegionPredicate(WhereRegionPredicate {
+                            lifetime: folder.fold_lifetime(region_predicate.lifetime),
+                            bounds: region_predicate.bounds
+                                .lift(|b| folder.fold_lifetime(b)),
+                        })
+                    }
+                    EqPredicate(eq_predicate) => {
+                        EqPredicate(WhereEqPredicate {
+                            lhs_ty: folder.fold_ty(eq_predicate.lhs_ty),
+                            rhs_ty: folder.fold_ty(eq_predicate.rhs_ty),
+                        })
+                    }
+                }),
+        },
+    }
+}
+
+// -
+pub fn noop_fold_ty_param_bound<F: Folder>(folder: &mut F, bound: TyParamBound) -> TyParamBound {
+    use self::TyParamBound::*;
+    match bound {
+        Trait(ty, modifier) => Trait(folder.fold_poly_trait_ref(ty), modifier),
+        Region(lifetime) => Region(folder.fold_lifetime(lifetime)),
+    }
+}
+
+// -
+pub fn noop_fold_poly_trait_ref<F: Folder>(folder: &mut F, trait_ref: PolyTraitRef)
+                                           -> PolyTraitRef {
+    PolyTraitRef {
+        bound_lifetimes: trait_ref.bound_lifetimes
+            .lift(|bl| folder.fold_lifetime_def(bl)),
+        trait_ref: folder.fold_path(trait_ref.trait_ref),
+    }
+}
+
+// -
+pub fn noop_fold_variant_data<F: Folder>(folder: &mut F,
+                                         data: VariantData)
+                                         -> VariantData {
+    use self::VariantData::*;
+    match data {
+        Struct(fields) => Struct(fields.lift(|f| folder.fold_field(f))),
+        Tuple(fields) => Tuple(fields.lift(|f| folder.fold_field(f))),
+        Unit => Unit,
+    }
+}
+
+// -
+pub fn noop_fold_field<F: Folder>(folder: &mut F, field: Field) -> Field {
+    Field {
+        ident: field.ident.map(|i| folder.fold_ident(i)),
+        vis: noop_fold_vis(folder, field.vis),
+        attrs: field.attrs.lift(|a| folder.fold_attribute(a)),
+        ty: folder.fold_ty(field.ty),
+    }
+}
+
+// -
+pub fn noop_fold_variant<F: Folder>(folder: &mut F,
+                                    Variant { ident, attrs, data, discriminant }: Variant)
+                                    -> Variant {
+    Variant {
+        ident: folder.fold_ident(ident),
+        attrs: attrs.lift(|v| folder.fold_attribute(v)),
+        data: folder.fold_variant_data(data),
+        discriminant: discriminant.map(|ce| folder.fold_const_expr(ce)),
+    }
+}
+
+// -
+pub fn noop_fold_lifetime<F: Folder>(folder: &mut F, _lifetime: Lifetime) -> Lifetime {
+    Lifetime { ident: folder.fold_ident(_lifetime.ident) }
+}
+
+// -
+pub fn noop_fold_lifetime_def<F: Folder>(folder: &mut F,
+                                         LifetimeDef { attrs, lifetime, bounds }: LifetimeDef)
+                                         -> LifetimeDef {
+    LifetimeDef {
+        attrs: attrs.lift(|x| folder.fold_attribute(x)),
+        lifetime: folder.fold_lifetime(lifetime),
+        bounds: bounds.lift(|l| folder.fold_lifetime(l)),
+    }
+}
+
+// -
+pub fn noop_fold_path<F: Folder>(folder: &mut F, Path { global, segments }: Path) -> Path {
+    Path {
+        global: global,
+        segments: segments.lift(|s| folder.fold_path_segment(s)),
+    }
+}
+
+// -
+pub fn noop_fold_path_segment<F: Folder>(folder: &mut F,
+                                         PathSegment { ident, parameters }: PathSegment)
+                                         -> PathSegment {
+    PathSegment {
+        ident: folder.fold_ident(ident),
+        parameters: folder.fold_path_parameters(parameters),
+    }
+}
+
+// -
+pub fn noop_fold_path_parameters<F: Folder>(folder: &mut F,
+                                            path_parameters: PathParameters)
+                                            -> PathParameters {
+    use self::PathParameters::*;
+    match path_parameters {
+        AngleBracketed(d) => {
+            let AngleBracketedParameterData { lifetimes, types, bindings } = d;
+            AngleBracketed(AngleBracketedParameterData {
+                lifetimes: lifetimes.into_iter().map(|l| folder.fold_lifetime(l)).collect(),
+                types: types.lift(|ty| folder.fold_ty(ty)),
+                bindings: bindings.lift(|tb| folder.fold_assoc_type_binding(tb)),
+            })
+        }
+        Parenthesized(d) => {
+            let ParenthesizedParameterData { inputs, output } = d;
+            Parenthesized(ParenthesizedParameterData {
+                inputs: inputs.lift(|i| folder.fold_ty(i)),
+                output: output.map(|v| folder.fold_ty(v)),
+            })
+        }
+    }
+}
+
+// -
+pub fn noop_fold_assoc_type_binding<F: Folder>(folder: &mut F,
+                                               TypeBinding { ident, ty }: TypeBinding)
+                                               -> TypeBinding {
+    TypeBinding {
+        ident: folder.fold_ident(ident),
+        ty: folder.fold_ty(ty),
+    }
+
+}
+
+// -
+pub fn noop_fold_attribute<F: Folder>(_: &mut F, _attr: Attribute) -> Attribute {
+    _attr
+}
+
+// -
+pub fn noop_fold_fn_ret_ty<F: Folder>(folder: &mut F, ret_ty: FunctionRetTy) -> FunctionRetTy {
+    use self::FunctionRetTy::*;
+    match ret_ty {
+        Default => Default,
+        Ty(ty) => Ty(folder.fold_ty(ty)),
+    }
+}
+
+
+pub fn noop_fold_const_expr<F: Folder>(folder: &mut F, expr: ConstExpr) -> ConstExpr {
+    use self::ConstExpr::*;
+    match expr {
+        Call(f, args) => {
+            Call(f.lift(|e| folder.fold_const_expr(e)),
+                 args.lift(|v| folder.fold_const_expr(v)))
+        }
+        Binary(op, lhs, rhs) => {
+            Binary(op,
+                   lhs.lift(|e| folder.fold_const_expr(e)),
+                   rhs.lift(|e| folder.fold_const_expr(e)))
+        }
+        Unary(op, e) => Unary(op, e.lift(|e| folder.fold_const_expr(e))),
+        Lit(l) => Lit(folder.fold_lit(l)),
+        Cast(e, ty) => {
+            Cast(e.lift(|e| folder.fold_const_expr(e)),
+                 ty.lift(|v| folder.fold_ty(v)))
+        }
+        Path(p) => Path(folder.fold_path(p)),
+        Index(o, i) => {
+            Index(o.lift(|e| folder.fold_const_expr(e)),
+                  i.lift(|e| folder.fold_const_expr(e)))
+        }
+        Paren(no_op) => Paren(no_op.lift(|e| folder.fold_const_expr(e))),
+        Other(e) => {
+                #[cfg(feature = "full")]            {
+                Other(folder.fold_expr(e))
+            }
+                #[cfg(not(feature = "full"))]            {
+                Other(e)
+            }
+        }
+    }
+}
+pub fn noop_fold_lit<F: Folder>(_: &mut F, _lit: Lit) -> Lit {
+    _lit
+}
+
+pub fn noop_fold_tt<F: Folder>(folder: &mut F, tt: TokenTree) -> TokenTree {
+    use self::TokenTree::*;
+    use self::Token::*;
+    match tt {
+        Token(token) => Token(match token {
+            Literal(lit) => Literal(folder.fold_lit(lit)),
+            Ident(ident) => Ident(folder.fold_ident(ident)),
+            Lifetime(ident) => Lifetime(folder.fold_ident(ident)),
+            x => x,
+        }),
+        Delimited(super::Delimited{delim, tts}) => Delimited(super::Delimited{delim: delim, tts: tts.lift(|v| noop_fold_tt(folder, v))}),
+    }
+}
+
+pub fn noop_fold_mac<F: Folder>(folder: &mut F, Mac { path, tts }: Mac) -> Mac {
+    Mac {
+        path: folder.fold_path(path),
+        tts: tts.lift(|tt| noop_fold_tt(folder, tt)),
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn noop_fold_crate<F: Folder>(folder: &mut F, Crate { shebang, attrs, items }: Crate) -> Crate {
+    Crate {
+        shebang: shebang,
+        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+        items: items.lift(|i| folder.fold_item(i)),
+    }
+
+}
+
+#[cfg(feature = "full")]
+pub fn noop_fold_block<F: Folder>(folder: &mut F, block: Block) -> Block {
+    Block { stmts: block.stmts.lift(|s| folder.fold_stmt(s)) }
+}
+
+fn noop_fold_vis<F: Folder>(folder: &mut F, vis: Visibility) -> Visibility {
+    use self::Visibility::*;
+    match vis {
+        Crate => Crate,
+        Inherited => Inherited,
+        Public => Public,
+        Restricted(path) => Restricted(path.lift(|p| folder.fold_path(p))),
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn noop_fold_item<F: Folder>(folder: &mut F, Item { ident, vis, attrs, node }: Item) -> Item {
+    use self::ItemKind::*;
+    Item {
+        ident: folder.fold_ident(ident.clone()),
+        vis: noop_fold_vis(folder, vis),
+        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+        node: match node {
+            ExternCrate(name) => ExternCrate(name.map(|i| folder.fold_ident(i))),
+            Use(view_path) => Use(Box::new(folder.fold_view_path(*view_path))),
+            Static(ty, mutability, expr) => {
+                Static(Box::new(folder.fold_ty(*ty)),
+                       mutability,
+                       expr.lift(|e| folder.fold_expr(e)))
+            }
+            Const(ty, expr) => {
+                Const(ty.lift(|ty| folder.fold_ty(ty)),
+                      expr.lift(|e| folder.fold_expr(e)))
+            }
+            Fn(fn_decl, unsafety, constness, abi, generics, block) => {
+                Fn(fn_decl.lift(|v| folder.fold_fn_decl(v)),
+                   unsafety,
+                   constness,
+                   abi,
+                   folder.fold_generics(generics),
+                   block.lift(|v| folder.fold_block(v)))
+            }
+            Mod(items) => Mod(items.map(|items| items.lift(|i| folder.fold_item(i)))),
+            ForeignMod(super::ForeignMod { abi, items }) => {
+                ForeignMod(super::ForeignMod {
+                    abi: abi,
+                    items: items.lift(|foreign_item| folder.fold_foreign_item(foreign_item)),
+                })
+            }
+            Ty(ty, generics) => {
+                Ty(ty.lift(|ty| folder.fold_ty(ty)),
+                   folder.fold_generics(generics))
+            }
+            Enum(variants, generics) => {
+                Enum(variants.lift(|v| folder.fold_variant(v, generics.clone())),
+                     folder.fold_generics(generics))
+            }
+            Struct(variant_data, generics) => {
+                Struct(folder.fold_variant_data(variant_data, ident, generics.clone()),
+                       folder.fold_generics(generics))
+            }
+            Union(variant_data, generics) => {
+                Union(folder.fold_variant_data(variant_data, ident, generics.clone()),
+                      folder.fold_generics(generics))
+            }
+            Trait(unsafety, generics, typbs, trait_items) => {
+                Trait(unsafety,
+                      folder.fold_generics(generics),
+                      typbs.lift(|typb| folder.fold_ty_param_bound(typb)),
+                      trait_items.lift(|ti| folder.fold_trait_item(ti)))
+            }
+            DefaultImpl(unsafety, path) => DefaultImpl(unsafety, folder.fold_path(path)),
+            Impl(unsafety, impl_polarity, generics, path, ty, impl_items) => {
+                Impl(unsafety,
+                     impl_polarity,
+                     folder.fold_generics(generics),
+                     path.map(|p| folder.fold_path(p)),
+                     ty.lift(|ty| folder.fold_ty(ty)),
+                     impl_items.lift(|i| folder.fold_impl_item(i)))
+            }
+            Mac(mac) => Mac(folder.fold_mac(mac)),
+        },
+    }
+}
+
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_expr<F: Folder>(folder: &mut F, Expr { node, attrs }: Expr) -> Expr {
+    use self::ExprKind::*;
+    Expr {
+        node: match node {
+            ExprKind::Box(e) => ExprKind::Box(e.lift(|e| folder.fold_expr(e))),
+            InPlace(place, value) => {
+                InPlace(place.lift(|e| folder.fold_expr(e)),
+                        value.lift(|e| folder.fold_expr(e)))
+            }
+            Array(array) => Array(array.lift(|e| folder.fold_expr(e))),
+            Call(function, args) => {
+                Call(function.lift(|e| folder.fold_expr(e)),
+                     args.lift(|e| folder.fold_expr(e)))
+            }
+            MethodCall(method, tys, args) => {
+                MethodCall(folder.fold_ident(method),
+                           tys.lift(|t| folder.fold_ty(t)),
+                           args.lift(|e| folder.fold_expr(e)))
+            }
+            Tup(args) => Tup(args.lift(|e| folder.fold_expr(e))),
+            Binary(bop, lhs, rhs) => {
+                Binary(bop,
+                       lhs.lift(|e| folder.fold_expr(e)),
+                       rhs.lift(|e| folder.fold_expr(e)))
+            }
+            Unary(uop, e) => Unary(uop, e.lift(|e| folder.fold_expr(e))),
+            Lit(lit) => Lit(folder.fold_lit(lit)),
+            Cast(e, ty) => {
+                Cast(e.lift(|e| folder.fold_expr(e)),
+                     ty.lift(|t| folder.fold_ty(t)))
+            }
+            Type(e, ty) => {
+                Type(e.lift(|e| folder.fold_expr(e)),
+                     ty.lift(|t| folder.fold_ty(t)))
+            }
+            If(e, if_block, else_block) => {
+                If(e.lift(|e| folder.fold_expr(e)),
+                   folder.fold_block(if_block),
+                   else_block.map(|v| v.lift(|e| folder.fold_expr(e))))
+            }
+            IfLet(pat, expr, block, else_block) => {
+                IfLet(pat.lift(|p| folder.fold_pat(p)),
+                      expr.lift(|e| folder.fold_expr(e)),
+                      folder.fold_block(block),
+                      else_block.map(|v| v.lift(|e| folder.fold_expr(e))))
+            }
+            While(e, block, label) => {
+                While(e.lift(|e| folder.fold_expr(e)),
+                      folder.fold_block(block),
+                      label.map(|i| folder.fold_ident(i)))
+            }
+            WhileLet(pat, expr, block, label) => {
+                WhileLet(pat.lift(|p| folder.fold_pat(p)),
+                         expr.lift(|e| folder.fold_expr(e)),
+                         folder.fold_block(block),
+                         label.map(|i| folder.fold_ident(i)))
+            }
+            ForLoop(pat, expr, block, label) => {
+                ForLoop(pat.lift(|p| folder.fold_pat(p)),
+                        expr.lift(|e| folder.fold_expr(e)),
+                        folder.fold_block(block),
+                        label.map(|i| folder.fold_ident(i)))
+            }
+            Loop(block, label) => {
+                Loop(folder.fold_block(block),
+                     label.map(|i| folder.fold_ident(i)))
+            }
+            Match(e, arms) => {
+                Match(e.lift(|e| folder.fold_expr(e)),
+                      arms.lift(|Arm { attrs, pats, guard, body }: Arm| {
+                    Arm {
+                        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+                        pats: pats.lift(|p| folder.fold_pat(p)),
+                        guard: guard.map(|v| v.lift(|e| folder.fold_expr(e))),
+                        body: body.lift(|e| folder.fold_expr(e)),
+                    }
+                }))
+            }
+            Closure(capture_by, fn_decl, expr) => {
+                Closure(capture_by,
+                        fn_decl.lift(|v| folder.fold_fn_decl(v)),
+                        expr.lift(|e| folder.fold_expr(e)))
+            }
+            Block(unsafety, block) => Block(unsafety, folder.fold_block(block)),
+            Assign(lhs, rhs) => {
+                Assign(lhs.lift(|e| folder.fold_expr(e)),
+                       rhs.lift(|e| folder.fold_expr(e)))
+            }
+            AssignOp(bop, lhs, rhs) => {
+                AssignOp(bop,
+                         lhs.lift(|e| folder.fold_expr(e)),
+                         rhs.lift(|e| folder.fold_expr(e)))
+            }
+            Field(expr, name) => Field(expr.lift(|e| folder.fold_expr(e)), folder.fold_ident(name)),
+            TupField(expr, index) => TupField(expr.lift(|e| folder.fold_expr(e)), index),
+            Index(expr, index) => {
+                Index(expr.lift(|e| folder.fold_expr(e)),
+                      index.lift(|e| folder.fold_expr(e)))
+            }
+            Range(lhs, rhs, limits) => {
+                Range(lhs.map(|v| v.lift(|e| folder.fold_expr(e))),
+                      rhs.map(|v| v.lift(|e| folder.fold_expr(e))),
+                      limits)
+            }
+            Path(qself, path) => {
+                Path(qself.map(|v| noop_fold_qself(folder, v)),
+                     folder.fold_path(path))
+            }
+            AddrOf(mutability, expr) => AddrOf(mutability, expr.lift(|e| folder.fold_expr(e))),
+            Break(label, expr) => {
+                Break(label.map(|i| folder.fold_ident(i)),
+                      expr.map(|v| v.lift(|e| folder.fold_expr(e))))
+            }
+            Continue(label) => Continue(label.map(|i| folder.fold_ident(i))),
+            Ret(expr) => Ret(expr.map(|v| v.lift(|e| folder.fold_expr(e)))),
+            ExprKind::Mac(mac) => ExprKind::Mac(folder.fold_mac(mac)),
+            Struct(path, fields, expr) => {
+                Struct(folder.fold_path(path),
+                       fields.lift(|FieldValue { ident, expr, is_shorthand, attrs }: FieldValue| {
+                    FieldValue {
+                        ident: folder.fold_ident(ident),
+                        expr: folder.fold_expr(expr),
+                        is_shorthand: is_shorthand,
+                        attrs: attrs.lift(|v| folder.fold_attribute(v)),
+                    }
+                }),
+                       expr.map(|v| v.lift(|e| folder.fold_expr(e))))
+            }
+            Repeat(element, number) => {
+                Repeat(element.lift(|e| folder.fold_expr(e)),
+                       number.lift(|e| folder.fold_expr(e)))
+            }
+            Paren(expr) => Paren(expr.lift(|e| folder.fold_expr(e))),
+            Try(expr) => Try(expr.lift(|e| folder.fold_expr(e))),
+        },
+        attrs: attrs.into_iter().map(|a| folder.fold_attribute(a)).collect(),
+    }
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_foreign_item<F: Folder>(folder: &mut F,
+                                         ForeignItem { ident, attrs, node, vis }: ForeignItem)
+                                         -> ForeignItem {
+    ForeignItem {
+        ident: folder.fold_ident(ident),
+        attrs: attrs.into_iter().map(|a| folder.fold_attribute(a)).collect(),
+        node: match node {
+            ForeignItemKind::Fn(fn_dcl, generics) => {
+                ForeignItemKind::Fn(fn_dcl.lift(|v| folder.fold_fn_decl(v)),
+                                    folder.fold_generics(generics))
+            }
+            ForeignItemKind::Static(ty, mutability) => {
+                ForeignItemKind::Static(ty.lift(|v| folder.fold_ty(v)), mutability)
+            }
+        },
+        vis: noop_fold_vis(folder, vis),
+    }
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_pat<F: Folder>(folder: &mut F, pat: Pat) -> Pat {
+    use self::Pat::*;
+    match pat {
+        Wild => Wild,
+        Ident(binding_mode, ident, pat) => {
+            Ident(binding_mode,
+                  folder.fold_ident(ident),
+                  pat.map(|p| p.lift(|p| folder.fold_pat(p))))
+        }
+        Struct(path, field_patterns, dots) => {
+            Struct(folder.fold_path(path),
+                   field_patterns.lift(|FieldPat { ident, pat, is_shorthand, attrs }: FieldPat| {
+                    FieldPat {
+                        ident: folder.fold_ident(ident),
+                        pat: pat.lift(|p| folder.fold_pat(p)),
+                        is_shorthand: is_shorthand,
+                        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+                    }
+                }),
+                   dots)
+        }
+        TupleStruct(path, pats, len) => {
+            TupleStruct(folder.fold_path(path),
+                        pats.lift(|p| folder.fold_pat(p)),
+                        len)
+        }
+        Path(qself, path) => {
+            Path(qself.map(|v| noop_fold_qself(folder, v)),
+                 folder.fold_path(path))
+        }
+        Tuple(pats, len) => Tuple(pats.lift(|p| folder.fold_pat(p)), len),
+        Box(b) => Box(b.lift(|p| folder.fold_pat(p))),
+        Ref(b, mutability) => Ref(b.lift(|p| folder.fold_pat(p)), mutability),
+        Lit(expr) => Lit(expr.lift(|e| folder.fold_expr(e))),
+        Range(l, r) => {
+            Range(l.lift(|e| folder.fold_expr(e)),
+                  r.lift(|e| folder.fold_expr(e)))
+        }
+        Slice(lefts, pat, rights) => {
+            Slice(lefts.lift(|p| folder.fold_pat(p)),
+                  pat.map(|v| v.lift(|p| folder.fold_pat(p))),
+                  rights.lift(|p| folder.fold_pat(p)))
+        }
+        Mac(mac) => Mac(folder.fold_mac(mac)),
+    }
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_fn_decl<F: Folder>(folder: &mut F,
+                                    FnDecl { inputs, output, variadic }: FnDecl)
+                                    -> FnDecl {
+
+    FnDecl {
+        inputs: inputs.lift(|a| {
+            use self::FnArg::*;
+            match a {
+                SelfRef(lifetime, mutability) => {
+                    SelfRef(lifetime.map(|v| folder.fold_lifetime(v)), mutability)
+                }
+                SelfValue(mutability) => SelfValue(mutability),
+                Captured(pat, ty) => Captured(folder.fold_pat(pat), folder.fold_ty(ty)),
+                Ignored(ty) => Ignored(folder.fold_ty(ty)),
+            }
+        }),
+        output: folder.fold_fn_ret_ty(output),
+        variadic: variadic,
+    }
+
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_trait_item<F: Folder>(folder: &mut F,
+                                       TraitItem { ident, attrs, node }: TraitItem)
+                                       -> TraitItem {
+    use self::TraitItemKind::*;
+    TraitItem {
+        ident: folder.fold_ident(ident),
+        attrs: attrs.lift(|v| folder.fold_attribute(v)),
+        node: match node {
+            Const(ty, expr) => Const(folder.fold_ty(ty), expr.map(|v| folder.fold_expr(v))),
+            Method(sig, block) => {
+                Method(folder.fold_method_sig(sig),
+                       block.map(|v| folder.fold_block(v)))
+            }
+            Type(ty_pbs, ty) => {
+                Type(ty_pbs.lift(|v| folder.fold_ty_param_bound(v)),
+                     ty.map(|v| folder.fold_ty(v)))
+            }
+            Macro(mac) => Macro(folder.fold_mac(mac)),  
+        },
+    }
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_impl_item<F: Folder>(folder: &mut F,
+                                      ImplItem { ident, vis, defaultness, attrs, node }: ImplItem)
+                                      -> ImplItem {
+    use self::ImplItemKind::*;
+    ImplItem {
+        ident: folder.fold_ident(ident),
+        vis: noop_fold_vis(folder, vis),
+        defaultness: defaultness,
+        attrs: attrs.lift(|v| folder.fold_attribute(v)),
+        node: match node {
+            Const(ty, expr) => Const(folder.fold_ty(ty), folder.fold_expr(expr)),
+            Method(sig, block) => {
+                Method(folder.fold_method_sig(sig), folder.fold_block(block))
+            }
+            Type(ty) => Type(folder.fold_ty(ty)),
+            Macro(mac) => Macro(folder.fold_mac(mac)),
+        },
+    }
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_method_sig<F: Folder>(folder: &mut F, MethodSig{unsafety, constness, abi, decl, generics}:MethodSig) -> MethodSig {
+    MethodSig {
+        unsafety: unsafety,
+        constness: constness,
+        abi: abi,
+        decl: folder.fold_fn_decl(decl),
+        generics: folder.fold_generics(generics),
+    }
+
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_stmt<F: Folder>(folder: &mut F, stmt: Stmt) -> Stmt {
+    use self::Stmt::*;
+    match stmt {
+        Local(local) => Local(local.lift(|l| folder.fold_local(l))),
+        Item(item) => Item(item.lift(|v| folder.fold_item(v))),
+        Expr(expr) => Expr(expr.lift(|v| folder.fold_expr(v))),
+        Semi(expr) => Semi(expr.lift(|v| folder.fold_expr(v))),
+        Mac(mac_stmt) => {
+            Mac(mac_stmt.lift(|(mac, style, attrs)| {
+                (folder.fold_mac(mac), style, attrs.lift(|a| folder.fold_attribute(a)))
+            }))
+        }
+    }
+
+}
+
+// -
+#[cfg(feature = "full")]
+pub fn noop_fold_local<F: Folder>(folder: &mut F, Local { pat, ty, init, attrs }: Local) -> Local {
+    Local {
+        pat: pat.lift(|v| folder.fold_pat(v)),
+        ty: ty.map(|v| v.lift(|t| folder.fold_ty(t))),
+        init: init.map(|v| v.lift(|e| folder.fold_expr(e))),
+        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn noop_fold_view_path<F: Folder>(folder: &mut F, view_path: ViewPath) -> ViewPath {
+    use self::ViewPath::*;
+    match view_path {
+        Simple(path, ident) => Simple(folder.fold_path(path), ident.map(|i| folder.fold_ident(i))),
+        Glob(path) => Glob(folder.fold_path(path)),
+        List(path, items) => {
+            List(folder.fold_path(path),
+                 items.lift(|PathListItem { name, rename }: PathListItem| {
+                     PathListItem {
+                         name: folder.fold_ident(name),
+                         rename: rename.map(|i| folder.fold_ident(i)),
+                     }
+                 }))
+        }
+    }
+}