From ec82a79ebe77c6d0ad1da31a595593fce0b6a496 Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:52:21 +0000 Subject: [PATCH] refactor(ast_codegen): trim `r#` from start of field names (#4785) Some struct fields are reserved names e.g. `type`. They are written in source as `r#type`. Trim off the `r#` prefix in `FieldDef::name` and add it back when generating output. Main motivation is to have the unescaped field names in JSON schema. --- .../src/generators/assert_layouts.rs | 5 +++-- tasks/ast_codegen/src/schema/mod.rs | 5 ++++- tasks/ast_codegen/src/util.rs | 22 ++++++++++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tasks/ast_codegen/src/generators/assert_layouts.rs b/tasks/ast_codegen/src/generators/assert_layouts.rs index d6ee9e6fa6d7d..937aadde25136 100644 --- a/tasks/ast_codegen/src/generators/assert_layouts.rs +++ b/tasks/ast_codegen/src/generators/assert_layouts.rs @@ -1,11 +1,12 @@ use proc_macro2::TokenStream; -use quote::{format_ident, quote}; +use quote::quote; use syn::Type; use crate::{ codegen::LateCtx, output, schema::{FieldDef, ToType, TypeDef}, + util::ToIdent, Generator, GeneratorOutput, }; @@ -96,7 +97,7 @@ fn with_offsets_assertion( let assertions = fields.iter().zip(offsets).filter(|(field, _)| field.vis.is_pub()).map( |(field, offset)| { - let field = field.name.as_ref().map(|it| format_ident!("{it}")); + let field = field.name.as_ref().map(ToIdent::to_ident); quote! { assert!(offset_of!(#ty, #field) == #offset); } diff --git a/tasks/ast_codegen/src/schema/mod.rs b/tasks/ast_codegen/src/schema/mod.rs index 8b6406112443f..74d1dea0a988f 100644 --- a/tasks/ast_codegen/src/schema/mod.rs +++ b/tasks/ast_codegen/src/schema/mod.rs @@ -238,7 +238,10 @@ fn lower_inherit(inherit: &rust::Inherit, ctx: &codegen::EarlyCtx) -> InheritDef fn lower_field(field: &syn::Field, ctx: &codegen::EarlyCtx) -> FieldDef { FieldDef { - name: field.ident.as_ref().map(ToString::to_string), + name: field + .ident + .as_ref() + .map(|ident| ident.to_string().trim_start_matches("r#").to_string()), vis: Visibility::from(&field.vis), typ: create_type_ref(&field.ty, ctx), markers: parse_inner_markers(&field.attrs).unwrap(), diff --git a/tasks/ast_codegen/src/util.rs b/tasks/ast_codegen/src/util.rs index 0610ea72e02c8..52e48353e9fc8 100644 --- a/tasks/ast_codegen/src/util.rs +++ b/tasks/ast_codegen/src/util.rs @@ -282,12 +282,32 @@ impl TokenStreamExt for TokenStream { } } +// From https://doc.rust-lang.org/reference/keywords.html +#[rustfmt::skip] +static RESERVED_NAMES: &[&str] = &[ + // Strict keywords + "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", + "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", + "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", "async", + "await", "dyn", + // Reserved keywords + "abstract", "become", "box", "do", "final", "macro", "override", "priv", "typeof", "unsized", + "virtual", "yield", "try", + // Weak keywords + "macro_rules", "union", // "dyn" also listed as a weak keyword, but is already on strict list +]; + impl ToIdent for S where S: AsRef, { fn to_ident(&self) -> Ident { - format_ident!("{}", self.as_ref()) + let name = self.as_ref(); + if RESERVED_NAMES.contains(&name) { + format_ident!("r#{name}") + } else { + format_ident!("{name}") + } } }