Document syntax tree enums idiom
diff --git a/src/attr.rs b/src/attr.rs
index 429e058..bd104d8 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -258,6 +258,12 @@
     ///
     /// A name-value meta is like the `path = "..."` in `#[path =
     /// "sys/windows.rs"]`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Meta {
         pub Word(Ident),
         /// A structured list within an attribute, like `derive(Copy, Clone)`.
diff --git a/src/data.rs b/src/data.rs
index cfea802..77dc725 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -28,6 +28,12 @@
 
 ast_enum_of_structs! {
     /// Data stored within an enum variant or struct.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Fields {
         /// Named fields of a struct or struct variant such as `Point { x: f64,
         /// y: f64 }`.
@@ -71,6 +77,12 @@
 ast_enum_of_structs! {
     /// The visibility level of an item: inherited or `pub` or
     /// `pub(restricted)`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Visibility {
         /// A public visibility level: `pub`.
         pub Public(VisPublic {
diff --git a/src/derive.rs b/src/derive.rs
index fa635f4..ea8ffdc 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -31,6 +31,12 @@
 
 ast_enum_of_structs! {
     /// The storage of a struct, enum or union data structure.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Data {
         /// A struct input to a `proc_macro_derive` macro.
         pub Struct(DataStruct {
diff --git a/src/expr.rs b/src/expr.rs
index 975c635..5f48b2c 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -18,6 +18,88 @@
 
 ast_enum_of_structs! {
     /// A Rust expression.
+    ///
+    /// # Syntax tree enums
+    ///
+    /// This type is a syntax tree enum. In Syn this and other syntax tree enums
+    /// are designed to be traversed using the following rebinding idiom.
+    ///
+    /// ```
+    /// # use syn::Expr;
+    /// #
+    /// # fn example(expr: Expr) {
+    /// # const IGNORE: &str = stringify! {
+    /// let expr: Expr = /* ... */;
+    /// # };
+    /// match expr {
+    ///     Expr::MethodCall(expr) => {
+    ///         /* ... */
+    ///     }
+    ///     Expr::Cast(expr) => {
+    ///         /* ... */
+    ///     }
+    ///     Expr::IfLet(expr) => {
+    ///         /* ... */
+    ///     }
+    ///     /* ... */
+    ///     # _ => {}
+    /// }
+    /// # }
+    /// ```
+    ///
+    /// We begin with a variable `expr` of type `Expr` that has no fields
+    /// (because it is an enum), and by matching on it and rebinding a variable
+    /// with the same name `expr` we effectively imbue our variable with all of
+    /// the data fields provided by the variant that it turned out to be. So for
+    /// example above if we ended up in the `MethodCall` case then we get to use
+    /// `expr.receiver`, `expr.args` etc; if we ended up in the `IfLet` case we
+    /// get to use `expr.pat`, `expr.then_branch`, `expr.else_branch`.
+    ///
+    /// The pattern is similar if the input expression is borrowed:
+    ///
+    /// ```
+    /// # use syn::Expr;
+    /// #
+    /// # fn example(expr: &Expr) {
+    /// match *expr {
+    ///     Expr::MethodCall(ref expr) => {
+    /// #   }
+    /// #   _ => {}
+    /// # }
+    /// # }
+    /// ```
+    ///
+    /// This approach avoids repeating the variant names twice on every line.
+    ///
+    /// ```
+    /// # use syn::{Expr, ExprMethodCall};
+    /// #
+    /// # fn example(expr: Expr) {
+    /// # match expr {
+    /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { // repetitive
+    /// # }
+    /// # _ => {}
+    /// # }
+    /// # }
+    /// ```
+    ///
+    /// In general, the name to which a syntax tree enum variant is bound should
+    /// be a suitable name for the complete syntax tree enum type.
+    ///
+    /// ```
+    /// # use syn::{Expr, ExprField};
+    /// #
+    /// # fn example(discriminant: &ExprField) {
+    /// // Binding is called `base` which is the name I would use if I were
+    /// // assigning `*discriminant.base` without an `if let`.
+    /// if let Expr::Tuple(ref base) = *discriminant.base {
+    /// # }
+    /// # }
+    /// ```
+    ///
+    /// A sign that you may not be choosing the right variable names is if you
+    /// see names getting repeated in your code, like accessing
+    /// `receiver.receiver` or `pat.pat` or `cond.cond`.
     pub enum Expr {
         /// A box expression: `box f`.
         pub Box(ExprBox #full {
@@ -581,6 +663,12 @@
 ast_enum_of_structs! {
     /// A pattern in a local binding, function signature, match expression, or
     /// various other places.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     // Clippy false positive
     // https://github.com/Manishearth/rust-clippy/issues/1241
     #[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
diff --git a/src/generics.rs b/src/generics.rs
index ef48928..0e20052 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -24,6 +24,12 @@
 ast_enum_of_structs! {
     /// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
     /// `'a: 'b`, `const LEN: usize`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum GenericParam {
         /// A generic type parameter: `T: Into<String>`.
         pub Type(TypeParam {
@@ -187,6 +193,12 @@
 
 ast_enum_of_structs! {
     /// A single predicate in a `where` clause: `T: Deserialize<'de>`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum WherePredicate {
         /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
         pub Type(PredicateType {
diff --git a/src/item.rs b/src/item.rs
index 0cda50c..0bc57aa 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -19,6 +19,12 @@
 
 ast_enum_of_structs! {
     /// Things that can appear directly inside of a module or scope.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Item {
         /// An `extern crate` item: `extern crate serde`.
         pub ExternCrate(ItemExternCrate {
@@ -288,6 +294,12 @@
 
 ast_enum_of_structs! {
     /// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum UseTree {
         /// An identifier imported by a `use` item: `Type` or `Type as Renamed`.
         pub Path(UsePath {
@@ -308,6 +320,12 @@
 
 ast_enum_of_structs! {
     /// An item within an `extern` block.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum ForeignItem {
         /// A foreign function in an `extern` block.
         pub Fn(ForeignItemFn {
@@ -368,6 +386,12 @@
 
 ast_enum_of_structs! {
     /// An item declaration within the definition of a trait.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum TraitItem {
         /// An associated constant within the definition of a trait.
         pub Const(TraitItemConst {
@@ -436,6 +460,12 @@
 
 ast_enum_of_structs! {
     /// An item within an impl block.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum ImplItem {
         /// An associated constant within an impl block.
         pub Const(ImplItemConst {
@@ -535,6 +565,12 @@
     /// An argument in a function signature.
     ///
     /// E.g. `bar: usize` as in `fn foo(bar: usize)`
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum FnArg {
         /// Self captured by reference in a function signature: `&self` or `&mut
         /// self`.
diff --git a/src/lit.rs b/src/lit.rs
index 0d54641..56a354d 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -17,6 +17,12 @@
 
 ast_enum_of_structs! {
     /// A Rust literal such as a string or integer or boolean.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Lit {
         /// A UTF-8 string literal: `"foo"`.
         pub Str(LitStr #manual_extra_traits {
diff --git a/src/ty.rs b/src/ty.rs
index 9538260..39bae38 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -16,6 +16,12 @@
 
 ast_enum_of_structs! {
     /// The possible types that a Rust value could have.
+    ///
+    /// # Syntax tree enum
+    ///
+    /// This type is a [syntax tree enum].
+    ///
+    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
     pub enum Type {
         /// A dynamically sized slice type: `[T]`.
         pub Slice(TypeSlice {