diff --git a/full-moon-derive/src/node.rs b/full-moon-derive/src/node.rs
index 151784df..5b8beafe 100644
--- a/full-moon-derive/src/node.rs
+++ b/full-moon-derive/src/node.rs
@@ -30,21 +30,6 @@ fn token_getter(
     }
 }
 
-#[derive(PartialEq)]
-enum NodeHint {
-    FullRange,
-}
-
-impl Hint for NodeHint {
-    fn unit(name: String) -> Option<Self> {
-        if name == "full_range" {
-            Some(NodeHint::FullRange)
-        } else {
-            None
-        }
-    }
-}
-
 pub struct NodeGenerator;
 
 impl DeriveGenerator for NodeGenerator {
@@ -122,41 +107,29 @@ impl StructGenerator for StructRangeGenerator {
             .map(|field| field.ident.as_ref().unwrap())
             .collect::<Vec<_>>();
 
-        let full_range = strukt
-            .fields
-            .iter()
-            .find(|field| search_hint("node", &field.attrs) == Some(NodeHint::FullRange));
-
-        if let Some(full_range) = full_range {
-            let ident = full_range.ident.as_ref().unwrap();
-            quote! {
-                self.#ident.range()
-            }
-        } else {
-            let (mut start_position, mut end_position) = (
-                Vec::with_capacity(fields.len()),
-                Vec::with_capacity(fields.len()),
-            );
+        let (mut start_position, mut end_position) = (
+            Vec::with_capacity(fields.len()),
+            Vec::with_capacity(fields.len()),
+        );
 
-            for field in &fields {
-                start_position.push(quote! {
-                    .or_else(|| {
-                        self.#field.start_position()
-                    })
-                });
-            }
+        for field in &fields {
+            start_position.push(quote! {
+                .or_else(|| {
+                    self.#field.start_position()
+                })
+            });
+        }
 
-            for field in fields.iter().rev() {
-                end_position.push(quote! {
-                    .or_else(|| {
-                        self.#field.end_position()
-                    })
-                });
-            }
+        for field in fields.iter().rev() {
+            end_position.push(quote! {
+                .or_else(|| {
+                    self.#field.end_position()
+                })
+            });
+        }
 
-            quote! {
-                Some((None#(#start_position)*?, None#(#end_position)*?))
-            }
+        quote! {
+            Some((None#(#start_position)*?, None#(#end_position)*?))
         }
     }
 }
@@ -238,17 +211,7 @@ impl MatchEnumGenerator for EnumRangeGenerator {
             .map(|field| field.ident.as_ref().unwrap())
             .collect::<Vec<_>>();
 
-        let full_range = named
-            .named
-            .iter()
-            .find(|field| search_hint("node", &field.attrs) == Some(NodeHint::FullRange));
-
-        let body = if let Some(full_range) = full_range {
-            let ident = full_range.ident.as_ref().unwrap();
-            quote! {
-                #ident.range()
-            }
-        } else {
+        let body = {
             let (mut start_position, mut end_position) = (
                 Vec::with_capacity(fields.len()),
                 Vec::with_capacity(fields.len()),
diff --git a/full-moon-derive/src/visit.rs b/full-moon-derive/src/visit.rs
index ab671737..bf7cc523 100644
--- a/full-moon-derive/src/visit.rs
+++ b/full-moon-derive/src/visit.rs
@@ -1,7 +1,6 @@
 use crate::derive::*;
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
-use std::collections::HashMap;
 
 // Not 100% accurate, but it is to full-moon's codebase
 fn snake_case(pascal_case: &str) -> String {
@@ -22,7 +21,6 @@ fn snake_case(pascal_case: &str) -> String {
 
 #[derive(Debug, PartialEq)]
 enum VisitHint {
-    Contains(String),
     Skip,
     SkipVisitSelf,
     VisitAs(String),
@@ -32,8 +30,6 @@ impl Hint for VisitHint {
     fn key_value(key: String, value: String) -> Option<Self> {
         if key == "visit_as" {
             Some(VisitHint::VisitAs(value))
-        } else if key == "contains" {
-            Some(VisitHint::Contains(value))
         } else {
             None
         }
@@ -53,7 +49,6 @@ pub struct VisitGenerator;
 impl VisitGenerator {
     fn visit_fields(data_fields: &syn::Fields, prefix: TokenStream) -> TokenStream {
         let mut fields = Vec::new();
-        let mut contains = HashMap::new();
 
         for field in data_fields
             .iter()
@@ -62,28 +57,7 @@ impl VisitGenerator {
             let ident = field.ident.as_ref().unwrap();
             let token_stream = quote! { #prefix#ident };
 
-            if let Some(VisitHint::Contains(contains_node)) = search_hint("visit", &field.attrs) {
-                contains.insert(contains_node, ident);
-            } else if let Some(contains_me) = contains.remove(&ident.to_string()) {
-                fields.push(quote! {
-                    #prefix#contains_me.tokens.0
-                });
-
-                fields.push(token_stream);
-
-                fields.push(quote! {
-                    #prefix#contains_me.tokens.1
-                });
-            } else {
-                fields.push(token_stream);
-            }
-        }
-
-        if !contains.is_empty() {
-            panic!(
-                "#[visit(contains = \"...\")] used in wrong order: {:?}",
-                contains
-            );
+            fields.push(token_stream);
         }
 
         quote! {
diff --git a/full-moon/src/ast/mod.rs b/full-moon/src/ast/mod.rs
index 2f33925b..001133ac 100644
--- a/full-moon/src/ast/mod.rs
+++ b/full-moon/src/ast/mod.rs
@@ -29,9 +29,6 @@ pub mod types;
 #[cfg(feature = "roblox")]
 use types::*;
 
-#[cfg(feature = "roblox")]
-mod type_visitors;
-
 #[cfg(feature = "lua52")]
 pub mod lua52;
 #[cfg(feature = "lua52")]
@@ -156,24 +153,15 @@ impl Default for Return {
 }
 
 /// Fields of a [`TableConstructor`]
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum Field {
     /// A key in the format of `[expression] = value`
-    #[display(
-        fmt = "{}{}{}{}{}",
-        "brackets.tokens().0",
-        "key",
-        "brackets.tokens().1",
-        "equal",
-        "value"
-    )]
+    #[display(fmt = "{}{}{}", "key", "equal", "value")]
     ExpressionKey {
-        /// The `[...]` part of `[expression] = value`
-        brackets: ContainedSpan,
-        /// The `expression` part of `[expression] = value`
-        key: Expression,
+        /// The `[expression]` part of `[expression] = value`
+        key: ContainedSpan<Expression>,
         /// The `=` part of `[expression] = value`
         equal: TokenReference,
         /// The `value` part of `[expression] = value`
@@ -199,12 +187,9 @@ pub enum Field {
 /// A table being constructed, such as `{ 1, 2, 3 }` or `{ a = 1 }`
 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
-#[display(fmt = "{}{}{}", "braces.tokens().0", "fields", "braces.tokens().1")]
+#[display(fmt = "{}", "fields")]
 pub struct TableConstructor {
-    #[node(full_range)]
-    #[visit(contains = "fields")]
-    braces: ContainedSpan,
-    fields: Punctuated<Field>,
+    fields: ContainedSpan<Punctuated<Field>>,
 }
 
 impl TableConstructor {
@@ -212,32 +197,36 @@ impl TableConstructor {
     /// Brace tokens are followed by spaces, such that { `fields` }
     pub fn new() -> Self {
         Self {
-            braces: ContainedSpan::new(
+            fields: ContainedSpan::new(
                 TokenReference::symbol("{ ").unwrap(),
+                Punctuated::new(),
                 TokenReference::symbol(" }").unwrap(),
             ),
-            fields: Punctuated::new(),
         }
     }
 
     /// The braces of the constructor
-    pub fn braces(&self) -> &ContainedSpan {
-        &self.braces
+    pub fn braces(&self) -> (&TokenReference, &TokenReference) {
+        self.fields.tokens()
     }
 
     /// Returns the [`Punctuated`] sequence of the fields used to create the table
     pub fn fields(&self) -> &Punctuated<Field> {
-        &self.fields
+        self.fields.inner()
     }
 
     /// Returns a new TableConstructor with the given braces
-    pub fn with_braces(self, braces: ContainedSpan) -> Self {
-        Self { braces, ..self }
+    pub fn with_braces(self, braces: (TokenReference, TokenReference)) -> Self {
+        Self {
+            fields: self.fields.with_tokens(braces),
+        }
     }
 
     /// Returns a new TableConstructor with the given fields
     pub fn with_fields(self, fields: Punctuated<Field>) -> Self {
-        Self { fields, ..self }
+        Self {
+            fields: self.fields.with_inner(fields),
+        }
     }
 }
 
@@ -248,7 +237,7 @@ impl Default for TableConstructor {
 }
 
 /// An expression, mostly useful for getting values
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[cfg_attr(feature = "serde", serde(untagged))]
 #[non_exhaustive]
@@ -265,19 +254,8 @@ pub enum Expression {
     },
 
     /// A statement in parentheses, such as `(#list)`
-    #[display(
-        fmt = "{}{}{}",
-        "contained.tokens().0",
-        "expression",
-        "contained.tokens().1"
-    )]
-    Parentheses {
-        /// The parentheses of the `ParenExpression`
-        #[node(full_range)]
-        contained: ContainedSpan,
-        /// The expression inside the parentheses
-        expression: Box<Expression>,
-    },
+    #[display(fmt = "{}", "_0")]
+    Parentheses(ContainedSpan<Box<Expression>>),
 
     /// A unary operation, such as `#list`
     #[display(fmt = "{}{}", "unop", "expression")]
@@ -415,23 +393,14 @@ pub enum Prefix {
 
 /// The indexing of something, such as `x.y` or `x["y"]`
 /// Values of variants are the keys, such as `"y"`
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum Index {
     /// Indexing in the form of `x["y"]`
-    #[display(
-        fmt = "{}{}{}",
-        "brackets.tokens().0",
-        "expression",
-        "brackets.tokens().1"
-    )]
-    Brackets {
-        /// The `[...]` part of `["y"]`
-        brackets: ContainedSpan,
-        /// The `"y"` part of `["y"]`
-        expression: Expression,
-    },
+    /// The `["y"]` part of the index.
+    #[display(fmt = "{}", "_0")]
+    Brackets(ContainedSpan<Expression>),
 
     /// Indexing in the form of `x.y`
     #[display(fmt = "{}{}", "dot", "name")]
@@ -444,24 +413,13 @@ pub enum Index {
 }
 
 /// Arguments used for a function
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum FunctionArgs {
     /// Used when a function is called in the form of `call(1, 2, 3)`
-    #[display(
-        fmt = "{}{}{}",
-        "parentheses.tokens().0",
-        "arguments",
-        "parentheses.tokens().1"
-    )]
-    Parentheses {
-        /// The `(...) part of (1, 2, 3)`
-        #[node(full_range)]
-        parentheses: ContainedSpan,
-        /// The `1, 2, 3` part of `1, 2, 3`
-        arguments: Punctuated<Expression>,
-    },
+    #[display(fmt = "{}", "_0")]
+    Parentheses(ContainedSpan<Punctuated<Expression>>),
     /// Used when a function is called in the form of `call "foobar"`
     #[display(fmt = "{}", "_0")]
     String(TokenReference),
@@ -1266,8 +1224,7 @@ pub enum Call {
 #[derive(Clone, Debug, PartialEq, Node)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 pub struct FunctionBody {
-    parameters_parentheses: ContainedSpan,
-    parameters: Punctuated<Parameter>,
+    parameters: ContainedSpan<Punctuated<Parameter>>,
 
     #[cfg(feature = "roblox")]
     type_specifiers: Vec<Option<TypeSpecifier>>,
@@ -1284,11 +1241,11 @@ impl FunctionBody {
     /// Returns a new empty FunctionBody
     pub fn new() -> Self {
         Self {
-            parameters_parentheses: ContainedSpan::new(
+            parameters: ContainedSpan::new(
                 TokenReference::symbol("(").unwrap(),
+                Punctuated::new(),
                 TokenReference::symbol(")").unwrap(),
             ),
-            parameters: Punctuated::new(),
 
             #[cfg(feature = "roblox")]
             type_specifiers: Vec::new(),
@@ -1302,13 +1259,13 @@ impl FunctionBody {
     }
 
     /// The parentheses of the parameters
-    pub fn parameters_parentheses(&self) -> &ContainedSpan {
-        &self.parameters_parentheses
+    pub fn parameters_parentheses(&self) -> (&TokenReference, &TokenReference) {
+        self.parameters.tokens()
     }
 
     /// Returns the [`Punctuated`] sequence of the parameters for the function declaration
     pub fn parameters(&self) -> &Punctuated<Parameter> {
-        &self.parameters
+        self.parameters.inner()
     }
 
     /// The code of a function body
@@ -1337,16 +1294,8 @@ impl FunctionBody {
         self.return_type.as_ref()
     }
 
-    /// Returns a new FunctionBody with the given parentheses for the parameters
-    pub fn with_parameters_parentheses(self, parameters_parentheses: ContainedSpan) -> Self {
-        Self {
-            parameters_parentheses,
-            ..self
-        }
-    }
-
     /// Returns a new FunctionBody with the given parameters
-    pub fn with_parameters(self, parameters: Punctuated<Parameter>) -> Self {
+    pub fn with_parameters(self, parameters: ContainedSpan<Punctuated<Parameter>>) -> Self {
         Self { parameters, ..self }
     }
 
@@ -1391,9 +1340,9 @@ impl fmt::Display for FunctionBody {
         write!(
             formatter,
             "{}{}{}{}{}{}",
-            self.parameters_parentheses.tokens().0,
-            join_type_specifiers(&self.parameters, self.type_specifiers()),
-            self.parameters_parentheses.tokens().1,
+            self.parameters.start,
+            join_type_specifiers(self.parameters.inner(), self.type_specifiers()),
+            self.parameters.end,
             display_option(self.return_type.as_ref()),
             self.block,
             self.end_token
@@ -1404,12 +1353,8 @@ impl fmt::Display for FunctionBody {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(
             formatter,
-            "{}{}{}{}{}",
-            self.parameters_parentheses.tokens().0,
-            self.parameters,
-            self.parameters_parentheses.tokens().1,
-            self.block,
-            self.end_token
+            "{}{}{}",
+            self.parameters, self.block, self.end_token
         )
     }
 }
@@ -1838,13 +1783,11 @@ impl FunctionCall {
         FunctionCall {
             prefix,
             suffixes: vec![Suffix::Call(Call::AnonymousCall(
-                FunctionArgs::Parentheses {
-                    arguments: Punctuated::new(),
-                    parentheses: ContainedSpan::new(
-                        TokenReference::symbol("(").unwrap(),
-                        TokenReference::symbol(")").unwrap(),
-                    ),
-                },
+                FunctionArgs::Parentheses(ContainedSpan::new(
+                    TokenReference::symbol("(").unwrap(),
+                    Punctuated::new(),
+                    TokenReference::symbol(")").unwrap(),
+                )),
             ))],
         }
     }
@@ -2378,10 +2321,11 @@ mod tests {
         LocalFunction::new(token.clone());
         MethodCall::new(
             token.clone(),
-            FunctionArgs::Parentheses {
-                arguments: Punctuated::new(),
-                parentheses: ContainedSpan::new(token.clone(), token.clone()),
-            },
+            FunctionArgs::Parentheses(ContainedSpan::new(
+                token.clone(),
+                Punctuated::new(),
+                token.clone(),
+            )),
         );
         NumericFor::new(token.clone(), expression.clone(), expression.clone());
         Repeat::new(expression.clone());
diff --git a/full-moon/src/ast/parsers.rs b/full-moon/src/ast/parsers.rs
index af426466..3e8914a3 100644
--- a/full-moon/src/ast/parsers.rs
+++ b/full-moon/src/ast/parsers.rs
@@ -154,8 +154,7 @@ define_parser!(ParseField, Field, |_, state| {
         return Ok((
             state,
             Field::ExpressionKey {
-                brackets: ContainedSpan::new(start_bracket, end_bracket),
-                key,
+                key: ContainedSpan::new(start_bracket, key, end_bracket),
                 equal,
                 value,
             },
@@ -210,8 +209,7 @@ define_parser!(ParseTableConstructor, TableConstructor, |_, state| {
     Ok((
         state,
         TableConstructor {
-            braces: ContainedSpan::new(start_brace, end_brace),
-            fields,
+            fields: ContainedSpan::new(start_brace, fields, end_brace),
         },
     ))
 });
@@ -244,10 +242,11 @@ define_parser!(ParseParenExpression, Expression, |_, state| {
 
     Ok((
         state,
-        Expression::Parentheses {
-            contained: ContainedSpan::new(left_paren, right_paren),
-            expression: Box::new(expression),
-        },
+        Expression::Parentheses(ContainedSpan::new(
+            left_paren,
+            Box::new(expression),
+            right_paren,
+        )),
     ))
 });
 
@@ -410,10 +409,7 @@ define_parser!(
         );
         Ok((
             state,
-            Index::Brackets {
-                brackets: ContainedSpan::new(start_bracket, end_bracket),
-                expression,
-            },
+            Index::Brackets(ContainedSpan::new(start_bracket, expression, end_bracket)),
         ))
     } else if let Ok((state, dot)) = ParseSymbol(Symbol::Dot).parse(state) {
         let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected name");
@@ -443,10 +439,7 @@ define_parser!(
         );
         Ok((
             state,
-            FunctionArgs::Parentheses {
-                arguments,
-                parentheses: ContainedSpan::new(left_paren, right_paren),
-            },
+            FunctionArgs::Parentheses(ContainedSpan::new(left_paren, arguments, right_paren)),
         ))
     } else if let Ok((state, table_constructor)) = keep_going!(ParseTableConstructor.parse(state)) {
         Ok((state, FunctionArgs::TableConstructor(table_constructor)))
@@ -836,8 +829,7 @@ define_parser!(ParseFunctionBody, FunctionBody, |_, state| {
     Ok((
         state,
         FunctionBody {
-            parameters_parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
-            parameters,
+            parameters: ContainedSpan::new(start_parenthese, parameters, end_parenthese),
             block,
             end_token,
             #[cfg(feature = "roblox")]
@@ -1173,8 +1165,7 @@ define_roblox_parser!(
         Ok((
             state,
             GenericDeclaration {
-                arrows: ContainedSpan::new(start_arrow, end_arrow),
-                generics,
+                generics: ContainedSpan::new(start_arrow, generics, end_arrow),
             },
         ))
     }
@@ -1299,8 +1290,7 @@ cfg_if::cfg_if! {
                         state,
                         IndexedTypeInfo::Generic {
                             base: identifier,
-                            arrows: ContainedSpan::new(start_arrow, end_arrow),
-                            generics,
+                            generics: ContainedSpan::new(start_arrow, generics, end_arrow),
                         },
                     )
                 } else {
@@ -1326,10 +1316,7 @@ cfg_if::cfg_if! {
             let mut types = Punctuated::new();
             types.push(Pair::new(type_info, None));
 
-            Ok((state, TypeInfo::Tuple {
-                parentheses: ContainedSpan::new(this.0.clone(), end_parenthese),
-                types,
-            }))
+            Ok((state, TypeInfo::Tuple (ContainedSpan::new(this.0.clone(), types, end_parenthese))))
         });
 
         #[derive(Clone, Debug, PartialEq)]
@@ -1388,8 +1375,7 @@ cfg_if::cfg_if! {
             Ok((
                 state,
                 TypeInfo::Callback {
-                    arguments: types,
-                    parentheses: ContainedSpan::new(this.0.clone(), end_parenthese),
+                    arguments: ContainedSpan::new(this.0.clone(), types, end_parenthese),
                     arrow,
                     return_type: Box::new(return_value),
                 },
@@ -1428,8 +1414,7 @@ cfg_if::cfg_if! {
                         state,
                         TypeInfo::Typeof {
                             typeof_token: identifier,
-                            parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
-                            inner: Box::new(expression),
+                            expression: ContainedSpan::new(start_parenthese, Box::new(expression), end_parenthese),
                         },
                     )
                 } else if let Ok((state, punctuation)) = ParseSymbol(Symbol::Dot).parse(state)
@@ -1466,8 +1451,7 @@ cfg_if::cfg_if! {
                         state,
                         TypeInfo::Generic {
                             base: identifier,
-                            arrows: ContainedSpan::new(start_arrow, end_arrow),
-                            generics,
+                            generics: ContainedSpan::new(start_arrow, generics, end_arrow),
                         },
                     )
                 } else {
@@ -1480,16 +1464,16 @@ cfg_if::cfg_if! {
                     // Single token lookahead: see if we have a `->` ahead. If we do, we need to parse this
                     // as a callback type, using what we already have from the parentheses type
                     if let Ok((state, arrow)) = ParseSymbol(Symbol::ThinArrow).parse(state) {
-                        // Unwrap the parsed parentheses type into its parentheses and its enclosed type
-                        let (parentheses, arguments) = match parentheses_type {
-                            TypeInfo::Tuple { parentheses, types } => {
-                                // `types` is currently `Punctuated<TypeInfo>`, but we need to map it to `Punctuated<TypeArgument>`
+                        let arguments = match parentheses_type {
+                            TypeInfo::Tuple (types) => {
+                                // `types.inner()` is currently `Punctuated<TypeInfo>`, but we need to map it to `Punctuated<TypeArgument>`
                                 // where each argument has no name.
-                                let arguments = types.into_pairs().map(|pair| pair.map(|type_info| TypeArgument {
+                                let arguments = types.inner.into_pairs().map(|pair| pair.map(|type_info| TypeArgument {
                                     name: None,
                                     type_info
                                 })).collect::<Punctuated<_>>();
-                                (parentheses, arguments)
+
+                                ContainedSpan::new(types.start, arguments, types.end)
                             },
                             _ => unreachable!("parsed a non-tuple as a parentheses type"),
                         };
@@ -1504,7 +1488,6 @@ cfg_if::cfg_if! {
                             state,
                             TypeInfo::Callback {
                                 arguments,
-                                parentheses,
                                 arrow,
                                 return_type: Box::new(return_value),
                             },
@@ -1527,10 +1510,7 @@ cfg_if::cfg_if! {
 
                     (
                         state,
-                        TypeInfo::Table {
-                            braces: ContainedSpan::new(start_brace, end_brace),
-                            fields,
-                        },
+                        TypeInfo::Table (ContainedSpan::new(start_brace, fields, end_brace))
                     )
                 } else {
                     let (state, type_info) = expect!(
@@ -1547,10 +1527,7 @@ cfg_if::cfg_if! {
 
                     (
                         state,
-                        TypeInfo::Array {
-                            braces: ContainedSpan::new(start_brace, end_brace),
-                            type_info: Box::new(type_info)
-                        },
+                        TypeInfo::Array (ContainedSpan::new(start_brace, Box::new(type_info), end_brace))
                     )
                 }
             } else if matches!(this.0, TypeInfoContext::ParenthesesType | TypeInfoContext::ReturnType) {
@@ -1620,8 +1597,7 @@ cfg_if::cfg_if! {
                     Ok((
                         state,
                         TypeInfo::Callback {
-                            arguments,
-                            parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
+                            arguments: ContainedSpan::new(start_parenthese, arguments, end_parenthese),
                             arrow,
                             return_type: Box::new(return_value),
                         },
@@ -1629,10 +1605,7 @@ cfg_if::cfg_if! {
                 } else {
                     Ok((
                         state,
-                        TypeInfo::Tuple {
-                            parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
-                            types,
-                        },
+                        TypeInfo::Tuple (ContainedSpan::new(start_parenthese, types, end_parenthese))
                     ))
                 }
             } else {
@@ -1744,10 +1717,7 @@ cfg_if::cfg_if! {
 
                 Ok((
                     state,
-                    TypeFieldKey::IndexSignature {
-                        brackets: ContainedSpan::new(start_bracket, end_bracket),
-                        inner,
-                    },
+                    TypeFieldKey::IndexSignature (ContainedSpan::new(start_bracket, inner, end_bracket))
                 ))
             } else {
                 Err(InternalAstError::NoMatch)
diff --git a/full-moon/src/ast/span.rs b/full-moon/src/ast/span.rs
index 4b9fd05e..9443631d 100644
--- a/full-moon/src/ast/span.rs
+++ b/full-moon/src/ast/span.rs
@@ -7,53 +7,98 @@
 //!
 //! Contained spans don't contain the inner data, just the start and end bounds.
 use crate::{
-    node::{Node, Tokens},
+    node::{Node, TokenItem, Tokens},
     private::Sealed,
     tokenizer::{Position, TokenReference},
+    visitors::{Visit, VisitMut, Visitor, VisitorMut},
 };
 
-use full_moon_derive::Visit;
+use derive_more::Display;
 #[cfg(feature = "serde")]
 use serde::{Deserialize, Serialize};
 
 /// A contained span with the beginning and ending bounds.
 /// Refer to the [module documentation](index.html) for more details.
-#[derive(Clone, Debug, PartialEq, Visit)]
+#[derive(Clone, Debug, Display, PartialEq)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
-pub struct ContainedSpan {
-    pub(crate) tokens: (TokenReference, TokenReference),
+#[display(fmt = "{}{}{}", "start", "inner", "end")]
+pub struct ContainedSpan<T> {
+    pub(crate) start: TokenReference,
+    pub(crate) inner: T,
+    pub(crate) end: TokenReference,
 }
 
-impl ContainedSpan {
+impl<T> ContainedSpan<T> {
     /// Creates a contained span from the start and end bounds
-    pub fn new(start: TokenReference, end: TokenReference) -> Self {
-        Self {
-            tokens: (start, end),
-        }
+    pub fn new(start: TokenReference, inner: T, end: TokenReference) -> Self {
+        Self { start, inner, end }
     }
 
     /// Returns the start and end bounds in a tuple as references
     pub fn tokens(&self) -> (&TokenReference, &TokenReference) {
-        (&self.tokens.0, &self.tokens.1)
+        (&self.start, &self.end)
+    }
+
+    /// Returns the node contained within the ContainedSpan
+    pub fn inner(&self) -> &T {
+        &self.inner
+    }
+
+    /// Creates a new ContainedSpan with the given containing tokens
+    pub fn with_tokens(self, tokens: (TokenReference, TokenReference)) -> Self {
+        Self {
+            start: tokens.0,
+            end: tokens.1,
+            ..self
+        }
+    }
+
+    /// Creates a new ContainedSpan with the given node contained within it
+    pub fn with_inner(self, inner: T) -> Self {
+        Self { inner, ..self }
     }
 }
 
-impl Node for ContainedSpan {
+impl<T: Node> Node for ContainedSpan<T> {
     fn start_position(&self) -> Option<Position> {
-        self.tokens.0.start_position()
+        self.start.start_position()
     }
 
     fn end_position(&self) -> Option<Position> {
-        self.tokens.1.end_position()
+        self.end.end_position()
     }
 
     fn similar(&self, other: &Self) -> bool {
-        self.tokens.0.similar(&other.tokens.0) && self.tokens.1.similar(&other.tokens.1)
+        self.start.similar(&other.start)
+            && self.end.similar(&other.end)
+            && self.inner.similar(&other.inner)
     }
 
     fn tokens(&self) -> Tokens {
-        self.tokens.tokens()
+        let mut items = self.start.tokens().items;
+        items.append(&mut self.inner.tokens().items);
+        items.push(TokenItem::TokenReference(&self.end));
+
+        Tokens { items }
     }
 }
 
-impl Sealed for ContainedSpan {}
+impl<T> Sealed for ContainedSpan<T> {}
+
+impl<T: Visit> Visit for ContainedSpan<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        self.start.visit(visitor);
+        self.inner.visit(visitor);
+        self.end.visit(visitor);
+    }
+}
+
+impl<T: VisitMut> VisitMut for ContainedSpan<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        ContainedSpan {
+            start: self.start.visit_mut(visitor),
+            inner: self.inner.visit_mut(visitor),
+            end: self.end.visit_mut(visitor),
+        }
+    }
+}
diff --git a/full-moon/src/ast/type_visitors.rs b/full-moon/src/ast/type_visitors.rs
deleted file mode 100644
index c3407c45..00000000
--- a/full-moon/src/ast/type_visitors.rs
+++ /dev/null
@@ -1,331 +0,0 @@
-// Implementations of Visit and VisitMut that are not able to be automatically derived yet.
-// Ideally everything would be derived.
-use super::*;
-use crate::visitors::{Visit, VisitMut, Visitor, VisitorMut};
-
-// The following have `ContainedSpan`, which when automatically derived will visit the tokens containing
-// before they visit what they're actually containing.
-// For example, if there is an AST node that represents `(foo)`...
-// Then visitors will visit this as `()foo`.
-// This is fixed for structs with `#[visit(contains = "...")], but this is not supported on enums.
-impl Visit for TypeInfo {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_type_info(self);
-        match self {
-            TypeInfo::Array { braces, type_info } => {
-                braces.tokens.0.visit(visitor);
-                type_info.visit(visitor);
-                braces.tokens.1.visit(visitor);
-            }
-            TypeInfo::Basic(__self_0) => {
-                __self_0.visit(visitor);
-            }
-            TypeInfo::Callback {
-                parentheses,
-                arguments,
-                arrow,
-                return_type,
-            } => {
-                parentheses.tokens.0.visit(visitor);
-                arguments.visit(visitor);
-                parentheses.tokens.1.visit(visitor);
-                arrow.visit(visitor);
-                return_type.visit(visitor);
-            }
-            TypeInfo::Generic {
-                base,
-                arrows,
-                generics,
-            } => {
-                base.visit(visitor);
-                arrows.tokens.0.visit(visitor);
-                generics.visit(visitor);
-                arrows.tokens.1.visit(visitor);
-            }
-            TypeInfo::Module {
-                module,
-                punctuation,
-                type_info,
-            } => {
-                module.visit(visitor);
-                punctuation.visit(visitor);
-                type_info.visit(visitor);
-            }
-            TypeInfo::Optional {
-                base,
-                question_mark,
-            } => {
-                base.visit(visitor);
-                question_mark.visit(visitor);
-            }
-            TypeInfo::Table { braces, fields } => {
-                braces.tokens.0.visit(visitor);
-                fields.visit(visitor);
-                braces.tokens.1.visit(visitor);
-            }
-            TypeInfo::Typeof {
-                typeof_token,
-                parentheses,
-                inner,
-            } => {
-                typeof_token.visit(visitor);
-                parentheses.tokens.0.visit(visitor);
-                inner.visit(visitor);
-                parentheses.tokens.1.visit(visitor);
-            }
-            TypeInfo::Tuple { parentheses, types } => {
-                parentheses.tokens.0.visit(visitor);
-                types.visit(visitor);
-                parentheses.tokens.1.visit(visitor);
-            }
-            TypeInfo::Union { left, pipe, right } => {
-                left.visit(visitor);
-                pipe.visit(visitor);
-                right.visit(visitor);
-            }
-            TypeInfo::Intersection {
-                left,
-                ampersand,
-                right,
-            } => {
-                left.visit(visitor);
-                ampersand.visit(visitor);
-                right.visit(visitor);
-            }
-            TypeInfo::Variadic { ellipse, type_info } => {
-                ellipse.visit(visitor);
-                type_info.visit(visitor);
-            }
-        };
-        visitor.visit_type_info_end(self);
-    }
-}
-
-impl VisitMut for TypeInfo {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_type_info(self);
-        self = match self {
-            TypeInfo::Array {
-                mut braces,
-                mut type_info,
-            } => {
-                braces.tokens.0 = braces.tokens.0.visit_mut(visitor);
-                type_info = type_info.visit_mut(visitor);
-                braces.tokens.1 = braces.tokens.1.visit_mut(visitor);
-
-                TypeInfo::Array { braces, type_info }
-            }
-            TypeInfo::Basic(__self_0) => TypeInfo::Basic(__self_0.visit_mut(visitor)),
-            TypeInfo::Callback {
-                mut parentheses,
-                mut arguments,
-                mut arrow,
-                mut return_type,
-            } => {
-                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
-                arguments = arguments.visit_mut(visitor);
-                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
-                arrow = arrow.visit_mut(visitor);
-                return_type = return_type.visit_mut(visitor);
-
-                TypeInfo::Callback {
-                    parentheses,
-                    arguments,
-                    arrow,
-                    return_type,
-                }
-            }
-
-            TypeInfo::Generic {
-                mut base,
-                mut arrows,
-                mut generics,
-            } => {
-                base = base.visit_mut(visitor);
-                arrows.tokens.0 = arrows.tokens.0.visit_mut(visitor);
-                generics = generics.visit_mut(visitor);
-                arrows.tokens.1 = arrows.tokens.1.visit_mut(visitor);
-
-                TypeInfo::Generic {
-                    arrows,
-                    base,
-                    generics,
-                }
-            }
-
-            TypeInfo::Module {
-                mut module,
-                mut punctuation,
-                mut type_info,
-            } => {
-                module = module.visit_mut(visitor);
-                punctuation = punctuation.visit_mut(visitor);
-                type_info = type_info.visit_mut(visitor);
-
-                TypeInfo::Module {
-                    module,
-                    punctuation,
-                    type_info,
-                }
-            }
-
-            TypeInfo::Optional {
-                base,
-                question_mark,
-            } => TypeInfo::Optional {
-                base: base.visit_mut(visitor),
-                question_mark: question_mark.visit_mut(visitor),
-            },
-
-            TypeInfo::Table {
-                mut braces,
-                mut fields,
-            } => {
-                braces.tokens.0 = braces.tokens.0.visit_mut(visitor);
-                fields = fields.visit_mut(visitor);
-                braces.tokens.1 = braces.tokens.1.visit_mut(visitor);
-
-                TypeInfo::Table { braces, fields }
-            }
-
-            TypeInfo::Typeof {
-                mut typeof_token,
-                mut parentheses,
-                mut inner,
-            } => {
-                typeof_token = typeof_token.visit_mut(visitor);
-                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
-                inner = inner.visit_mut(visitor);
-                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
-
-                TypeInfo::Typeof {
-                    typeof_token,
-                    parentheses,
-                    inner,
-                }
-            }
-
-            TypeInfo::Tuple {
-                mut parentheses,
-                mut types,
-            } => {
-                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
-                types = types.visit_mut(visitor);
-                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
-
-                TypeInfo::Tuple { parentheses, types }
-            }
-
-            TypeInfo::Union { left, pipe, right } => TypeInfo::Union {
-                left: left.visit_mut(visitor),
-                pipe: pipe.visit_mut(visitor),
-                right: right.visit_mut(visitor),
-            },
-
-            TypeInfo::Intersection {
-                left,
-                ampersand,
-                right,
-            } => TypeInfo::Intersection {
-                left: left.visit_mut(visitor),
-                ampersand: ampersand.visit_mut(visitor),
-                right: right.visit_mut(visitor),
-            },
-
-            TypeInfo::Variadic { ellipse, type_info } => TypeInfo::Variadic {
-                ellipse: ellipse.visit_mut(visitor),
-                type_info: type_info.visit_mut(visitor),
-            },
-        };
-        self = visitor.visit_type_info_end(self);
-        self
-    }
-}
-
-impl Visit for IndexedTypeInfo {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_indexed_type_info(self);
-        match self {
-            IndexedTypeInfo::Basic(__self_0) => {
-                __self_0.visit(visitor);
-            }
-            IndexedTypeInfo::Generic {
-                base,
-                arrows,
-                generics,
-            } => {
-                base.visit(visitor);
-                arrows.tokens.0.visit(visitor);
-                generics.visit(visitor);
-                arrows.tokens.1.visit(visitor);
-            }
-        };
-        visitor.visit_indexed_type_info_end(self);
-    }
-}
-
-impl VisitMut for IndexedTypeInfo {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_indexed_type_info(self);
-        self = match self {
-            IndexedTypeInfo::Basic(__self_0) => IndexedTypeInfo::Basic(__self_0.visit_mut(visitor)),
-
-            IndexedTypeInfo::Generic {
-                mut base,
-                mut arrows,
-                mut generics,
-            } => {
-                base = base.visit_mut(visitor);
-                arrows.tokens.0 = arrows.tokens.0.visit_mut(visitor);
-                generics = generics.visit_mut(visitor);
-                arrows.tokens.1 = arrows.tokens.1.visit_mut(visitor);
-
-                IndexedTypeInfo::Generic {
-                    arrows,
-                    base,
-                    generics,
-                }
-            }
-        };
-        self = visitor.visit_indexed_type_info_end(self);
-        self
-    }
-}
-
-impl Visit for TypeFieldKey {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_type_field_key(self);
-        match self {
-            TypeFieldKey::Name(__self_0) => {
-                __self_0.visit(visitor);
-            }
-            TypeFieldKey::IndexSignature { brackets, inner } => {
-                brackets.tokens.0.visit(visitor);
-                inner.visit(visitor);
-                brackets.tokens.1.visit(visitor);
-            }
-        };
-        visitor.visit_type_field_key_end(self);
-    }
-}
-
-impl VisitMut for TypeFieldKey {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_type_field_key(self);
-        self = match self {
-            TypeFieldKey::Name(__self_0) => TypeFieldKey::Name(__self_0.visit_mut(visitor)),
-            TypeFieldKey::IndexSignature {
-                mut brackets,
-                mut inner,
-            } => {
-                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
-                inner = inner.visit_mut(visitor);
-                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
-
-                TypeFieldKey::IndexSignature { brackets, inner }
-            }
-        };
-        self = visitor.visit_type_field_key_end(self);
-        self
-    }
-}
diff --git a/full-moon/src/ast/types.rs b/full-moon/src/ast/types.rs
index 3328875e..11fc5ff6 100644
--- a/full-moon/src/ast/types.rs
+++ b/full-moon/src/ast/types.rs
@@ -5,37 +5,23 @@ use crate::{util::display_option, ShortString};
 use derive_more::Display;
 
 /// Any type, such as `string`, `boolean?`, `number | boolean`, etc.
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum TypeInfo {
     /// A shorthand type annotating the structure of an array: { number }
-    #[display(fmt = "{}{}{}", "braces.tokens().0", "type_info", "braces.tokens().1")]
-    Array {
-        /// The braces (`{}`) containing the type info.
-        braces: ContainedSpan,
-        /// The type info for the values in the Array
-        type_info: Box<TypeInfo>,
-    },
+    #[display(fmt = "{}", "_0")]
+    Array(ContainedSpan<Box<TypeInfo>>),
 
     /// A standalone type, such as `string` or `Foo`.
     #[display(fmt = "{}", "_0")]
     Basic(TokenReference),
 
     /// A callback type, such as `(string, number) => boolean`.
-    #[display(
-        fmt = "{}{}{}{}{}",
-        "parentheses.tokens().0",
-        "arguments",
-        "parentheses.tokens().1",
-        "arrow",
-        "return_type"
-    )]
+    #[display(fmt = "{}{}{}", "arguments", "arrow", "return_type")]
     Callback {
-        /// The parentheses for the arguments.
-        parentheses: ContainedSpan,
         /// The argument types: `(string, number)`.
-        arguments: Punctuated<TypeArgument>,
+        arguments: ContainedSpan<Punctuated<TypeArgument>>,
         /// The "thin arrow" (`->`) in between the arguments and the return type.
         arrow: TokenReference,
         /// The return type: `boolean`.
@@ -43,20 +29,12 @@ pub enum TypeInfo {
     },
 
     /// A type using generics, such as `map<number, string>`.
-    #[display(
-        fmt = "{}{}{}{}",
-        "base",
-        "arrows.tokens().0",
-        "generics",
-        "arrows.tokens().1"
-    )]
+    #[display(fmt = "{}{}", "base", "generics")]
     Generic {
         /// The type that has generics: `map`.
         base: TokenReference,
-        /// The arrows (`<>`) containing the type parameters.
-        arrows: ContainedSpan,
-        /// The type parameters: `number, string`.
-        generics: Punctuated<TypeInfo>,
+        /// The type parameters: `<number, string>`.
+        generics: ContainedSpan<Punctuated<TypeInfo>>,
     },
 
     /// An intersection type: `string & number`, denoting both types.
@@ -91,44 +69,21 @@ pub enum TypeInfo {
     },
 
     /// A type annotating the structure of a table: { foo: number, bar: string }
-    #[display(fmt = "{}{}{}", "braces.tokens().0", "fields", "braces.tokens().1")]
-    Table {
-        /// The braces (`{}`) containing the fields.
-        braces: ContainedSpan,
-        /// The fields: `foo: number, bar: string`.
-        fields: Punctuated<TypeField>,
-    },
+    #[display(fmt = "{}", "_0")]
+    Table(ContainedSpan<Punctuated<TypeField>>),
 
     /// A type in the form of `typeof(foo)`.
-    #[display(
-        fmt = "{}{}{}{}",
-        "typeof_token",
-        "parentheses.tokens().0",
-        "inner",
-        "parentheses.tokens().1"
-    )]
+    #[display(fmt = "{}{}", "typeof_token", "expression")]
     Typeof {
         /// The token `typeof`.
         typeof_token: TokenReference,
-        /// The parentheses used to contain the expression.
-        parentheses: ContainedSpan,
-        /// The inner expression: `foo`.
-        inner: Box<Expression>,
+        /// The expression: `(foo)`.
+        expression: ContainedSpan<Box<Expression>>,
     },
 
     /// A tuple expression: `(string, number)`.
-    #[display(
-        fmt = "{}{}{}",
-        "parentheses.tokens().0",
-        "types",
-        "parentheses.tokens().1"
-    )]
-    Tuple {
-        /// The parentheses used to contain the types
-        parentheses: ContainedSpan,
-        /// The types: `(string, number)`.
-        types: Punctuated<TypeInfo>,
-    },
+    #[display(fmt = "{}", "_0")]
+    Tuple(ContainedSpan<Punctuated<TypeInfo>>),
 
     /// A union type: `string | number`, denoting one or the other.
     #[display(fmt = "{}{}{}", "left", "pipe", "right")]
@@ -152,7 +107,7 @@ pub enum TypeInfo {
 }
 
 /// A subset of TypeInfo that consists of items which can only be used as an index, such as `Foo` and `Foo<Bar>`,
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum IndexedTypeInfo {
@@ -161,20 +116,12 @@ pub enum IndexedTypeInfo {
     Basic(TokenReference),
 
     /// A type using generics, such as `map<number, string>`.
-    #[display(
-        fmt = "{}{}{}{}",
-        "base",
-        "arrows.tokens().0",
-        "generics",
-        "arrows.tokens().1"
-    )]
+    #[display(fmt = "{}{}", "base", "generics")]
     Generic {
         /// The type that has generics: `map`.
         base: TokenReference,
-        /// The arrows (`<>`) containing the type parameters.
-        arrows: ContainedSpan,
-        /// The type parameters: `number, string`.
-        generics: Punctuated<TypeInfo>,
+        /// The type parameters: `<number, string>`.
+        generics: ContainedSpan<Punctuated<TypeInfo>>,
     },
 }
 
@@ -234,7 +181,7 @@ impl TypeField {
 }
 
 /// A key in a [`TypeField`]. Can either be a name or an index signature.
-#[derive(Clone, Debug, Display, PartialEq, Node)]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
 #[non_exhaustive]
 pub enum TypeFieldKey {
@@ -243,14 +190,8 @@ pub enum TypeFieldKey {
     Name(TokenReference),
 
     /// An index signature, such as `[number]`.
-    #[display(fmt = "{}{}{}", "brackets.tokens().0", "inner", "brackets.tokens().1")]
-    IndexSignature {
-        /// The brackets (`[]`) used to contain the type.
-        brackets: ContainedSpan,
-
-        /// The type for the index signature, `number` in `[number]`.
-        inner: TypeInfo,
-    },
+    #[display(fmt = "{}", "_0")]
+    IndexSignature(ContainedSpan<TypeInfo>),
 }
 
 /// A type assertion using `::`, such as `:: number`.
@@ -389,43 +330,45 @@ impl TypeDeclaration {
 /// The generics used in a [`TypeDeclaration`].
 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
-#[display(fmt = "{}{}{}", "arrows.tokens().0", "generics", "arrows.tokens().1")]
+#[display(fmt = "{}", "generics")]
 pub struct GenericDeclaration {
-    #[visit(contains = "generics")]
-    pub(crate) arrows: ContainedSpan,
-    pub(crate) generics: Punctuated<TokenReference>,
+    pub(crate) generics: ContainedSpan<Punctuated<TokenReference>>,
 }
 
 impl GenericDeclaration {
     /// Creates a new GenericDeclaration
     pub fn new() -> Self {
         Self {
-            arrows: ContainedSpan::new(
+            generics: ContainedSpan::new(
                 TokenReference::symbol("<").unwrap(),
+                Punctuated::new(),
                 TokenReference::symbol(">").unwrap(),
             ),
-            generics: Punctuated::new(),
         }
     }
 
     /// The arrows (`<>`) containing the types.
-    pub fn arrows(&self) -> &ContainedSpan {
-        &self.arrows
+    pub fn arrows(&self) -> (&TokenReference, &TokenReference) {
+        self.generics.tokens()
     }
 
     /// The names of the generics: `T, U` in `<T, U>`.
     pub fn generics(&self) -> &Punctuated<TokenReference> {
-        &self.generics
+        self.generics.inner()
     }
 
     /// Returns a new GenericDeclaration with the given arrows containing the types
-    pub fn with_arrows(self, arrows: ContainedSpan) -> Self {
-        Self { arrows, ..self }
+    pub fn with_arrows(self, arrows: (TokenReference, TokenReference)) -> Self {
+        Self {
+            generics: self.generics.with_tokens(arrows),
+        }
     }
 
     /// Returns a new TypeDeclaration with the given names of the generics
     pub fn with_generics(self, generics: Punctuated<TokenReference>) -> Self {
-        Self { generics, ..self }
+        Self {
+            generics: self.generics.with_inner(generics),
+        }
     }
 }
 
diff --git a/full-moon/src/ast/visitors.rs b/full-moon/src/ast/visitors.rs
index 9c3ce051..022fb731 100644
--- a/full-moon/src/ast/visitors.rs
+++ b/full-moon/src/ast/visitors.rs
@@ -3,270 +3,11 @@
 use super::*;
 use crate::visitors::{Visit, VisitMut, Visitor, VisitorMut};
 
-// The following have `ContainedSpan`, which when automatically derived will visit the tokens containing
-// before they visit what they're actually containing.
-// For example, if there is an AST node that represents `(foo)`...
-// Then visitors will visit this as `()foo`.
-// This is fixed for structs with `#[visit(contains = "...")], but this is not supported on enums.
-
-impl Visit for Field {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_field(self);
-        match self {
-            Field::ExpressionKey {
-                brackets,
-                key,
-                equal,
-                value,
-            } => {
-                brackets.tokens.0.visit(visitor);
-                key.visit(visitor);
-                brackets.tokens.1.visit(visitor);
-                equal.visit(visitor);
-                value.visit(visitor);
-            }
-
-            Field::NameKey { key, equal, value } => {
-                key.visit(visitor);
-                equal.visit(visitor);
-                value.visit(visitor);
-            }
-
-            Field::NoKey(__self_0) => {
-                __self_0.visit(visitor);
-            }
-        };
-
-        visitor.visit_field_end(self);
-    }
-}
-
-impl VisitMut for Field {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_field(self);
-        self = match self {
-            Field::ExpressionKey {
-                mut brackets,
-
-                mut key,
-                equal,
-                value,
-            } => {
-                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
-                key = key.visit_mut(visitor);
-                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
-
-                Field::ExpressionKey {
-                    brackets,
-                    key,
-                    equal: equal.visit_mut(visitor),
-                    value: value.visit_mut(visitor),
-                }
-            }
-
-            Field::NameKey { key, equal, value } => Field::NameKey {
-                key: key.visit_mut(visitor),
-                equal: equal.visit_mut(visitor),
-                value: value.visit_mut(visitor),
-            },
-
-            Field::NoKey(__self_0) => Field::NoKey(__self_0.visit_mut(visitor)),
-        };
-
-        self = visitor.visit_field_end(self);
-        self
-    }
-}
-
-impl Visit for Expression {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_expression(self);
-        match self {
-            Expression::BinaryOperator { lhs, binop, rhs } => {
-                lhs.visit(visitor);
-                binop.visit(visitor);
-                rhs.visit(visitor);
-            }
-
-            Expression::Parentheses {
-                contained,
-                expression,
-            } => {
-                contained.tokens.0.visit(visitor);
-                expression.visit(visitor);
-                contained.tokens.1.visit(visitor);
-            }
-            Expression::UnaryOperator { unop, expression } => {
-                unop.visit(visitor);
-                expression.visit(visitor);
-            }
-            Expression::Value {
-                value,
-                #[cfg(feature = "roblox")]
-                type_assertion,
-            } => {
-                value.visit(visitor);
-                #[cfg(feature = "roblox")]
-                type_assertion.visit(visitor);
-            }
-        };
-
-        visitor.visit_expression_end(self);
-    }
-}
-
-impl VisitMut for Expression {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_expression(self);
-        self = match self {
-            Expression::BinaryOperator { lhs, binop, rhs } => Expression::BinaryOperator {
-                lhs: lhs.visit_mut(visitor),
-                binop: binop.visit_mut(visitor),
-                rhs: rhs.visit_mut(visitor),
-            },
-
-            Expression::Parentheses {
-                mut contained,
-                mut expression,
-            } => {
-                contained.tokens.0 = contained.tokens.0.visit_mut(visitor);
-                expression = expression.visit_mut(visitor);
-                contained.tokens.1 = contained.tokens.1.visit_mut(visitor);
-
-                Expression::Parentheses {
-                    contained,
-                    expression,
-                }
-            }
-
-            Expression::UnaryOperator { unop, expression } => Expression::UnaryOperator {
-                unop: unop.visit_mut(visitor),
-                expression: expression.visit_mut(visitor),
-            },
-
-            Expression::Value {
-                value,
-                #[cfg(feature = "roblox")]
-                type_assertion,
-            } => Expression::Value {
-                value: value.visit_mut(visitor),
-                #[cfg(feature = "roblox")]
-                type_assertion: type_assertion.visit_mut(visitor),
-            },
-        };
-
-        self = visitor.visit_expression_end(self);
-        self
-    }
-}
-
-impl Visit for Index {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_index(self);
-        match self {
-            Index::Brackets {
-                brackets,
-                expression,
-            } => {
-                brackets.tokens.0.visit(visitor);
-                expression.visit(visitor);
-                brackets.tokens.1.visit(visitor);
-            }
-            Index::Dot { dot, name } => {
-                dot.visit(visitor);
-                name.visit(visitor);
-            }
-        };
-
-        visitor.visit_index_end(self);
-    }
-}
-
-impl VisitMut for Index {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_index(self);
-        self = match self {
-            Index::Brackets {
-                mut brackets,
-                mut expression,
-            } => {
-                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
-                expression = expression.visit_mut(visitor);
-                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
-
-                Index::Brackets {
-                    brackets,
-                    expression,
-                }
-            }
-
-            Index::Dot { dot, name } => Index::Dot {
-                dot: dot.visit_mut(visitor),
-                name: name.visit_mut(visitor),
-            },
-        };
-
-        self = visitor.visit_index_end(self);
-        self
-    }
-}
-
-impl Visit for FunctionArgs {
-    fn visit<V: Visitor>(&self, visitor: &mut V) {
-        visitor.visit_function_args(self);
-        match self {
-            FunctionArgs::Parentheses {
-                parentheses,
-                arguments,
-            } => {
-                parentheses.tokens.0.visit(visitor);
-                arguments.visit(visitor);
-                parentheses.tokens.1.visit(visitor);
-            }
-            FunctionArgs::String(__self_0) => {
-                __self_0.visit(visitor);
-            }
-            FunctionArgs::TableConstructor(__self_0) => {
-                __self_0.visit(visitor);
-            }
-        };
-
-        visitor.visit_function_args_end(self);
-    }
-}
-
-impl VisitMut for FunctionArgs {
-    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
-        self = visitor.visit_function_args(self);
-        self = match self {
-            FunctionArgs::Parentheses {
-                mut parentheses,
-                mut arguments,
-            } => {
-                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
-                arguments = arguments.visit_mut(visitor);
-                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
-                FunctionArgs::Parentheses {
-                    parentheses,
-                    arguments,
-                }
-            }
-            FunctionArgs::String(__self_0) => FunctionArgs::String(__self_0.visit_mut(visitor)),
-            FunctionArgs::TableConstructor(__self_0) => {
-                FunctionArgs::TableConstructor(__self_0.visit_mut(visitor))
-            }
-        };
-
-        self = visitor.visit_function_args_end(self);
-        self
-    }
-}
-
 // The following contain type signatures, which are addendums to previous identities
 impl Visit for FunctionBody {
     fn visit<V: Visitor>(&self, visitor: &mut V) {
         visitor.visit_function_body(self);
-        self.parameters_parentheses.tokens.0.visit(visitor);
+        self.parameters.start.visit(visitor);
 
         let mut type_specifiers;
 
@@ -281,12 +22,12 @@ impl Visit for FunctionBody {
             type_specifiers = std::iter::repeat::<Option<Self>>(None);
         }
 
-        for parameter in &self.parameters {
+        for parameter in &self.parameters.inner {
             parameter.visit(visitor);
             type_specifiers.next().visit(visitor);
         }
 
-        self.parameters_parentheses.tokens.1.visit(visitor);
+        self.parameters.end.visit(visitor);
 
         #[cfg(feature = "roblox")]
         self.return_type.visit(visitor);
@@ -300,8 +41,7 @@ impl Visit for FunctionBody {
 impl VisitMut for FunctionBody {
     fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
         self = visitor.visit_function_body(self);
-        self.parameters_parentheses.tokens.0 =
-            self.parameters_parentheses.tokens.0.visit_mut(visitor);
+        self.parameters.start = self.parameters.start.visit_mut(visitor);
 
         let mut type_specifiers;
 
@@ -319,7 +59,7 @@ impl VisitMut for FunctionBody {
         let mut new_type_specifiers = Vec::new();
         let mut new_parameters = Punctuated::new();
 
-        for parameter_pair in self.parameters.into_pairs() {
+        for parameter_pair in self.parameters.inner.into_pairs() {
             let parameter_tuple = parameter_pair.into_tuple();
             let parameter = parameter_tuple.0.visit_mut(visitor);
 
@@ -333,15 +73,14 @@ impl VisitMut for FunctionBody {
             new_parameters.push(Pair::new(parameter, punctuation));
         }
 
-        self.parameters = new_parameters;
+        self.parameters.inner = new_parameters;
 
         #[cfg(feature = "roblox")]
         {
             self.type_specifiers = new_type_specifiers;
         }
 
-        self.parameters_parentheses.tokens.1 =
-            self.parameters_parentheses.tokens.1.visit_mut(visitor);
+        self.parameters.end = self.parameters.end.visit_mut(visitor);
 
         #[cfg(feature = "roblox")]
         {
diff --git a/full-moon/src/visitors.rs b/full-moon/src/visitors.rs
index 98431f1e..305b3cfe 100644
--- a/full-moon/src/visitors.rs
+++ b/full-moon/src/visitors.rs
@@ -1,5 +1,5 @@
 use crate::{
-    ast::{span::ContainedSpan, *},
+    ast::*,
     private::Sealed,
     tokenizer::{Token, TokenReference},
 };
@@ -219,7 +219,6 @@ create_visitor!(ast: {
     visit_assignment => Assignment,
     visit_block => Block,
     visit_call => Call,
-    visit_contained_span => ContainedSpan,
     visit_do => Do,
     visit_else_if => ElseIf,
     visit_eof => TokenReference,