diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index e1ad7aaf0..122c6b174 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -22,7 +22,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0.60", features = ["visit-mut"] } +syn = "1.0.60" [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/serde_derive/src/internals/receiver.rs b/serde_derive/src/internals/receiver.rs index a9c6f10a9..2b722d8f2 100644 --- a/serde_derive/src/internals/receiver.rs +++ b/serde_derive/src/internals/receiver.rs @@ -3,8 +3,10 @@ use proc_macro2::Span; use quote::ToTokens; use std::mem; use syn::punctuated::Punctuated; -use syn::visit_mut::{self, VisitMut}; -use syn::{parse_quote, DeriveInput, ExprPath, Path, PathArguments, QSelf, Type, TypePath}; +use syn::{ + parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro, + Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate, +}; pub fn replace_receiver(input: &mut DeriveInput) { let self_ty = { @@ -68,7 +70,7 @@ impl ReplaceReceiver<'_> { } } -impl VisitMut for ReplaceReceiver<'_> { +impl ReplaceReceiver<'_> { // `Self` -> `Receiver` fn visit_type_mut(&mut self, ty: &mut Type) { let span = if let Type::Path(node) = ty { @@ -79,7 +81,7 @@ impl VisitMut for ReplaceReceiver<'_> { return; } } else { - visit_mut::visit_type_mut(self, ty); + self.visit_type_mut_impl(ty); return; }; *ty = self.self_ty(span).into(); @@ -90,7 +92,7 @@ impl VisitMut for ReplaceReceiver<'_> { if ty.qself.is_none() { self.self_to_qself(&mut ty.qself, &mut ty.path); } - visit_mut::visit_type_path_mut(self, ty); + self.visit_type_path_mut_impl(ty); } // `Self::method` -> `::method` @@ -98,6 +100,188 @@ impl VisitMut for ReplaceReceiver<'_> { if expr.qself.is_none() { self.self_to_qself(&mut expr.qself, &mut expr.path); } - visit_mut::visit_expr_path_mut(self, expr); + self.visit_expr_path_mut_impl(expr); } + + // Everything below is simply traversing the syntax tree. + + fn visit_type_mut_impl(&mut self, ty: &mut Type) { + match ty { + Type::Array(ty) => { + self.visit_type_mut(&mut ty.elem); + self.visit_expr_mut(&mut ty.len); + } + Type::BareFn(ty) => { + for arg in &mut ty.inputs { + self.visit_type_mut(&mut arg.ty); + } + self.visit_return_type_mut(&mut ty.output); + } + Type::Group(ty) => self.visit_type_mut(&mut ty.elem), + Type::ImplTrait(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac), + Type::Paren(ty) => self.visit_type_mut(&mut ty.elem), + Type::Path(ty) => { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem), + Type::Reference(ty) => self.visit_type_mut(&mut ty.elem), + Type::Slice(ty) => self.visit_type_mut(&mut ty.elem), + Type::TraitObject(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Tuple(ty) => { + for elem in &mut ty.elems { + self.visit_type_mut(elem); + } + } + + Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {} + + #[cfg(test)] + Type::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => {} + } + } + + fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + + fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) { + if let Some(qself) = &mut expr.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut expr.path); + } + + fn visit_path_mut(&mut self, path: &mut Path) { + for segment in &mut path.segments { + self.visit_path_arguments_mut(&mut segment.arguments); + } + } + + fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) { + match arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(arguments) => { + for arg in &mut arguments.args { + match arg { + GenericArgument::Type(arg) => self.visit_type_mut(arg), + GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty), + GenericArgument::Lifetime(_) + | GenericArgument::Constraint(_) + | GenericArgument::Const(_) => {} + } + } + } + PathArguments::Parenthesized(arguments) => { + for argument in &mut arguments.inputs { + self.visit_type_mut(argument); + } + self.visit_return_type_mut(&mut arguments.output); + } + } + } + + fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) { + match return_type { + ReturnType::Default => {} + ReturnType::Type(_, output) => self.visit_type_mut(output), + } + } + + fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) { + match bound { + TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), + TypeParamBound::Lifetime(_) => {} + } + } + + fn visit_generics_mut(&mut self, generics: &mut Generics) { + for param in &mut generics.params { + match param { + GenericParam::Type(param) => { + for bound in &mut param.bounds { + self.visit_type_param_bound_mut(bound); + } + } + GenericParam::Lifetime(_) | GenericParam::Const(_) => {} + } + } + if let Some(where_clause) = &mut generics.where_clause { + for predicate in &mut where_clause.predicates { + match predicate { + WherePredicate::Type(predicate) => { + self.visit_type_mut(&mut predicate.bounded_ty); + for bound in &mut predicate.bounds { + self.visit_type_param_bound_mut(bound); + } + } + WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {} + } + } + } + } + + fn visit_data_mut(&mut self, data: &mut Data) { + match data { + Data::Struct(data) => { + for field in &mut data.fields { + self.visit_type_mut(&mut field.ty); + } + } + Data::Enum(data) => { + for variant in &mut data.variants { + for field in &mut variant.fields { + self.visit_type_mut(&mut field.ty); + } + } + } + Data::Union(_) => {} + } + } + + fn visit_expr_mut(&mut self, expr: &mut Expr) { + match expr { + Expr::Binary(expr) => { + self.visit_expr_mut(&mut expr.left); + self.visit_expr_mut(&mut expr.right); + } + Expr::Call(expr) => { + self.visit_expr_mut(&mut expr.func); + for arg in &mut expr.args { + self.visit_expr_mut(arg); + } + } + Expr::Cast(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_type_mut(&mut expr.ty); + } + Expr::Field(expr) => self.visit_expr_mut(&mut expr.base), + Expr::Index(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_expr_mut(&mut expr.index); + } + Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr), + Expr::Path(expr) => self.visit_expr_path_mut(expr), + Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr), + _ => {} + } + } + + fn visit_macro_mut(&mut self, _mac: &mut Macro) {} } diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index f84121564..81c9e20d5 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -16,7 +16,7 @@ path = "lib.rs" [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls", "visit-mut"] } +syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"]