Repository: serde-rs/serde
File: serde_derive/src/internals/attr.rs (Rust)

Code before:
                                    }
                                    Err(err) => cx.error_spanned_by(ser, err),
                                }
                            }
                            if let Some(de) = de {
                                match RenameRule::from_str(&de.value()) {
                                    Ok(rename_rule) => {
                                        rename_all_fields_de_rule.set(&meta.path, rename_rule);
                                    }
                                    Err(err) => {
                                        if !one_name {
                                            cx.error_spanned_by(de, err);
                                        }
                                    }
                                }
                            }
                        }
                        syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
                            let msg = "#[serde(rename_all_fields)] can only be used on enums";
                            cx.error_spanned_by(struct_token, msg);
                        }
                        syn::Data::Union(syn::DataUnion { union_token, .. }) => {
                            let msg = "#[serde(rename_all_fields)] can only be used on enums";
                            cx.error_spanned_by(union_token, msg);
                        }
                    }
                } else if meta.path == TRANSPARENT {
                    // #[serde(transparent)]
                    transparent.set_true(meta.path);
                } else if meta.path == DENY_UNKNOWN_FIELDS {
                    // #[serde(deny_unknown_fields)]
                    deny_unknown_fields.set_true(meta.path);
                } else if meta.path == DEFAULT {
                    if meta.input.peek(Token![=]) {
                        // #[serde(default = "...")]
                        if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
                            match &item.data {
                                syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
                                    syn::Fields::Named(_) => {
                                        default.set(&meta.path, Default::Path(path));
                                    }
                                    syn::Fields::Unnamed(_) | syn::Fields::Unit => {
                                        let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
                                        cx.error_spanned_by(fields, msg);
                                    }
                                },
                                syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
                                    let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
                                    cx.error_spanned_by(enum_token, msg);
                                }
                                syn::Data::Union(syn::DataUnion { union_token, .. }) => {

Review comment (suggestion):
I think using the `struct`/`union` token for the span of this error is not a good choice. The problem is not that the user wrote a struct. The problem is that the user wrote a `rename_all_fields` attribute on their struct. The fix is not for the user to turn their struct into an enum. The fix is to change the attribute. So the error should point to the attribute.

Code after:
                                        rename_all_fields_ser_rule.set(&meta.path, rename_rule);
                                    }
                                    Err(err) => cx.error_spanned_by(ser, err),
                                }
                            }
                            if let Some(de) = de {
                                match RenameRule::from_str(&de.value()) {
                                    Ok(rename_rule) => {
                                        rename_all_fields_de_rule.set(&meta.path, rename_rule);
                                    }
                                    Err(err) => {
                                        if !one_name {
                                            cx.error_spanned_by(de, err);
                                        }
                                    }
                                }
                            }
                        }
                        syn::Data::Struct(_) => {
                            let msg = "#[serde(rename_all_fields)] can only be used on enums";
                            cx.error_spanned_by(&meta.path, msg);
                        }
                        syn::Data::Union(_) => {
                            let msg = "#[serde(rename_all_fields)] can only be used on enums";
                            cx.error_spanned_by(&meta.path, msg);
                        }
                    }
                } else if meta.path == TRANSPARENT {
                    // #[serde(transparent)]
                    transparent.set_true(meta.path);
                } else if meta.path == DENY_UNKNOWN_FIELDS {
                    // #[serde(deny_unknown_fields)]
                    deny_unknown_fields.set_true(meta.path);
                } else if meta.path == DEFAULT {
                    if meta.input.peek(Token![=]) {
                        // #[serde(default = "...")]
                        if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
                            match &item.data {
                                syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
                                    syn::Fields::Named(_) => {
                                        default.set(&meta.path, Default::Path(path));
                                    }
                                    syn::Fields::Unnamed(_) | syn::Fields::Unit => {
                                        let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
                                        cx.error_spanned_by(fields, msg);
                                    }
                                },
                                syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
                                    let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
                                    cx.error_spanned_by(enum_token, msg);
                                }