Skip to content

Commit

Permalink
Remove dependency on syn/visit-mut feature
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Jan 25, 2021
1 parent 1f42358 commit e5efb6a
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 8 deletions.
2 changes: 1 addition & 1 deletion serde_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
196 changes: 190 additions & 6 deletions serde_derive/src/internals/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 {
Expand All @@ -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();
Expand All @@ -90,14 +92,196 @@ 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` -> `<Receiver>::method`
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
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) {}
}
2 changes: 1 addition & 1 deletion serde_derive_internals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

0 comments on commit e5efb6a

Please sign in to comment.