Skip to content

Commit ae38b27

Browse files
committed
add #[allow(deprecated)] to derive implementations
Allow deprecated in the `Serialize`/`Deserialize` derive implementations. This allows you to deprecate structs, enums, struct fields, or enum variants and not get compiler warnings/errors about use of deprecated thing. We only do this if `#[deprecated]` or `#[allow(deprecated)]` exist on the root object or the variants of the root object (if it is an enum). Resolves #2195
1 parent da3998a commit ae38b27

File tree

9 files changed

+164
-0
lines changed

9 files changed

+164
-0
lines changed

serde_derive/src/de.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::fragment::{Expr, Fragment, Match, Stmts};
22
use crate::internals::ast::{Container, Data, Field, Style, Variant};
3+
use crate::internals::deprecated::allow_deprecated;
34
use crate::internals::name::Name;
45
use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
56
use crate::{bound, dummy, pretend, this};
@@ -22,6 +23,8 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
2223
precondition(&ctxt, &cont);
2324
ctxt.check()?;
2425

26+
let allow_deprecated = allow_deprecated(input)?;
27+
2528
let ident = &cont.ident;
2629
let params = Parameters::new(&cont);
2730
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
@@ -34,6 +37,7 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
3437
let used = pretend::pretend_used(&cont, params.is_packed);
3538
quote! {
3639
#[automatically_derived]
40+
#allow_deprecated
3741
impl #de_impl_generics #ident #ty_generics #where_clause {
3842
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
3943
where
@@ -49,6 +53,7 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
4953

5054
quote! {
5155
#[automatically_derived]
56+
#allow_deprecated
5257
impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
5358
fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<Self, __D::Error>
5459
where
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use proc_macro2::TokenStream;
2+
use quote::quote;
3+
4+
pub fn allow_deprecated(input: &syn::DeriveInput) -> syn::Result<TokenStream> {
5+
if should_allow_deprecated(input)? {
6+
Ok(quote! { #[allow(deprecated)]})
7+
} else {
8+
Ok(TokenStream::default())
9+
}
10+
}
11+
12+
/// Determine if an `#[allow(deprecated)]` should be added to the derived impl.
13+
///
14+
/// This should happen if the derive input or a variant of the enum (if derive input is an enum)
15+
/// has on of:
16+
/// - `#[deprecated]`
17+
/// - `#[allow(deprecated)]`
18+
fn should_allow_deprecated(input: &syn::DeriveInput) -> syn::Result<bool> {
19+
if contains_deprecated_attrs(&input.attrs)? {
20+
return Ok(true);
21+
}
22+
if let syn::Data::Enum(data_enum) = &input.data {
23+
for variant in &data_enum.variants {
24+
if contains_deprecated_attrs(&variant.attrs)? {
25+
return Ok(true);
26+
}
27+
}
28+
}
29+
Ok(false)
30+
}
31+
32+
/// Check whether a set of attributes contains one of:
33+
/// - `#[deprecated]`
34+
/// - `#[allow(deprecated)]`
35+
fn contains_deprecated_attrs(attrs: &[syn::Attribute]) -> syn::Result<bool> {
36+
for attr in attrs {
37+
if let syn::Meta::Path(path) = &attr.meta {
38+
if path.is_ident("deprecated") {
39+
return Ok(true);
40+
}
41+
}
42+
if let syn::Meta::List(meta_list) = &attr.meta {
43+
if meta_list.path.is_ident("allow") {
44+
let mut deprecated_allowed = false;
45+
meta_list.parse_nested_meta(|meta| {
46+
if meta.path.is_ident("deprecated") {
47+
deprecated_allowed = true;
48+
}
49+
Ok(())
50+
})?;
51+
if deprecated_allowed {
52+
return Ok(true);
53+
}
54+
}
55+
}
56+
}
57+
Ok(false)
58+
}

serde_derive/src/internals/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod ast;
22
pub mod attr;
3+
pub mod deprecated;
34
pub mod name;
45

56
mod case;

serde_derive/src/ser.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::fragment::{Fragment, Match, Stmts};
22
use crate::internals::ast::{Container, Data, Field, Style, Variant};
3+
use crate::internals::deprecated::allow_deprecated;
34
use crate::internals::name::Name;
45
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
56
use crate::{bound, dummy, pretend, this};
@@ -18,6 +19,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
1819
};
1920
precondition(&ctxt, &cont);
2021
ctxt.check()?;
22+
let allow_deprecated = allow_deprecated(input)?;
2123

2224
let ident = &cont.ident;
2325
let params = Parameters::new(&cont);
@@ -30,6 +32,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
3032
let used = pretend::pretend_used(&cont, params.is_packed);
3133
quote! {
3234
#[automatically_derived]
35+
#allow_deprecated
3336
impl #impl_generics #ident #ty_generics #where_clause {
3437
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
3538
where
@@ -43,6 +46,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
4346
} else {
4447
quote! {
4548
#[automatically_derived]
49+
#allow_deprecated
4650
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
4751
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
4852
where

test_suite/tests/deprecated.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![deny(deprecated)]
2+
#![allow(dead_code)]
3+
4+
use serde_derive::{Deserialize, Serialize};
5+
6+
/// deprecated enum
7+
#[derive(Serialize, Deserialize)]
8+
#[deprecated]
9+
enum E1 {
10+
A,
11+
B,
12+
}
13+
14+
/// deprecated struct
15+
#[derive(Serialize, Deserialize)]
16+
#[deprecated]
17+
struct S1 {
18+
a: bool,
19+
}
20+
21+
/// deprecated enum variant
22+
#[derive(Serialize, Deserialize)]
23+
enum E2 {
24+
A,
25+
#[deprecated]
26+
B,
27+
}
28+
29+
/// deprecated struct field
30+
#[derive(Serialize, Deserialize)]
31+
struct S2 {
32+
#[deprecated]
33+
a: bool,
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![deny(deprecated)]
2+
3+
use serde::Deserializer;
4+
use serde_derive::Deserialize;
5+
6+
#[derive(Deserialize)]
7+
pub struct Struct {
8+
#[serde(deserialize_with = "deprecated_with")]
9+
pub field: i32,
10+
}
11+
12+
#[deprecated]
13+
fn deprecated_with<'de, D>(_deserializer: D) -> Result<i32, D::Error>
14+
where
15+
D: Deserializer<'de>,
16+
{
17+
unimplemented!()
18+
}
19+
20+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: use of deprecated function `deprecated_with`
2+
--> tests/ui/deprecated/deprecated_de_with.rs:8:32
3+
|
4+
8 | #[serde(deserialize_with = "deprecated_with")]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> tests/ui/deprecated/deprecated_de_with.rs:1:9
9+
|
10+
1 | #![deny(deprecated)]
11+
| ^^^^^^^^^^
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![deny(deprecated)]
2+
3+
use serde::Serializer;
4+
use serde_derive::Serialize;
5+
6+
#[derive(Serialize)]
7+
pub struct Struct {
8+
#[serde(serialize_with = "deprecated_with")]
9+
pub field: i32,
10+
}
11+
12+
#[deprecated]
13+
fn deprecated_with<S>(_field: &i32, _serializer: S) -> Result<S::Ok, S::Error>
14+
where
15+
S: Serializer,
16+
{
17+
unimplemented!()
18+
}
19+
20+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: use of deprecated function `deprecated_with`
2+
--> tests/ui/deprecated/deprecated_ser_with.rs:8:30
3+
|
4+
8 | #[serde(serialize_with = "deprecated_with")]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> tests/ui/deprecated/deprecated_ser_with.rs:1:9
9+
|
10+
1 | #![deny(deprecated)]
11+
| ^^^^^^^^^^

0 commit comments

Comments
 (0)