mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-14 11:41:01 +00:00
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
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use crate::fragment::{Expr, Fragment, Match, Stmts};
|
use crate::fragment::{Expr, Fragment, Match, Stmts};
|
||||||
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
|
use crate::internals::deprecated::allow_deprecated;
|
||||||
use crate::internals::name::Name;
|
use crate::internals::name::Name;
|
||||||
use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
|
use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
|
||||||
use crate::{bound, dummy, pretend, this};
|
use crate::{bound, dummy, pretend, this};
|
||||||
@@ -22,6 +23,8 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
|
|||||||
precondition(&ctxt, &cont);
|
precondition(&ctxt, &cont);
|
||||||
ctxt.check()?;
|
ctxt.check()?;
|
||||||
|
|
||||||
|
let allow_deprecated = allow_deprecated(input)?;
|
||||||
|
|
||||||
let ident = &cont.ident;
|
let ident = &cont.ident;
|
||||||
let params = Parameters::new(&cont);
|
let params = Parameters::new(&cont);
|
||||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||||
@@ -34,6 +37,7 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
|
|||||||
let used = pretend::pretend_used(&cont, params.is_packed);
|
let used = pretend::pretend_used(&cont, params.is_packed);
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
#allow_deprecated
|
||||||
impl #de_impl_generics #ident #ty_generics #where_clause {
|
impl #de_impl_generics #ident #ty_generics #where_clause {
|
||||||
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
|
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
|
||||||
where
|
where
|
||||||
@@ -49,6 +53,7 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<To
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
#allow_deprecated
|
||||||
impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
||||||
fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<Self, __D::Error>
|
fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<Self, __D::Error>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
pub fn allow_deprecated(input: &syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
|
if should_allow_deprecated(input)? {
|
||||||
|
Ok(quote! { #[allow(deprecated)]})
|
||||||
|
} else {
|
||||||
|
Ok(TokenStream::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine if an `#[allow(deprecated)]` should be added to the derived impl.
|
||||||
|
///
|
||||||
|
/// This should happen if the derive input or a variant of the enum (if derive input is an enum)
|
||||||
|
/// has on of:
|
||||||
|
/// - `#[deprecated]`
|
||||||
|
/// - `#[allow(deprecated)]`
|
||||||
|
fn should_allow_deprecated(input: &syn::DeriveInput) -> syn::Result<bool> {
|
||||||
|
if contains_deprecated_attrs(&input.attrs)? {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
if let syn::Data::Enum(data_enum) = &input.data {
|
||||||
|
for variant in &data_enum.variants {
|
||||||
|
if contains_deprecated_attrs(&variant.attrs)? {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether a set of attributes contains one of:
|
||||||
|
/// - `#[deprecated]`
|
||||||
|
/// - `#[allow(deprecated)]`
|
||||||
|
fn contains_deprecated_attrs(attrs: &[syn::Attribute]) -> syn::Result<bool> {
|
||||||
|
for attr in attrs {
|
||||||
|
if let syn::Meta::Path(path) = &attr.meta {
|
||||||
|
if path.is_ident("deprecated") {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let syn::Meta::List(meta_list) = &attr.meta {
|
||||||
|
if meta_list.path.is_ident("allow") {
|
||||||
|
let mut deprecated_allowed = false;
|
||||||
|
meta_list.parse_nested_meta(|meta| {
|
||||||
|
if meta.path.is_ident("deprecated") {
|
||||||
|
deprecated_allowed = true;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
if deprecated_allowed {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
pub mod deprecated;
|
||||||
pub mod name;
|
pub mod name;
|
||||||
|
|
||||||
mod case;
|
mod case;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::fragment::{Fragment, Match, Stmts};
|
use crate::fragment::{Fragment, Match, Stmts};
|
||||||
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
|
use crate::internals::deprecated::allow_deprecated;
|
||||||
use crate::internals::name::Name;
|
use crate::internals::name::Name;
|
||||||
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
|
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
|
||||||
use crate::{bound, dummy, pretend, this};
|
use crate::{bound, dummy, pretend, this};
|
||||||
@@ -18,6 +19,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
|||||||
};
|
};
|
||||||
precondition(&ctxt, &cont);
|
precondition(&ctxt, &cont);
|
||||||
ctxt.check()?;
|
ctxt.check()?;
|
||||||
|
let allow_deprecated = allow_deprecated(input)?;
|
||||||
|
|
||||||
let ident = &cont.ident;
|
let ident = &cont.ident;
|
||||||
let params = Parameters::new(&cont);
|
let params = Parameters::new(&cont);
|
||||||
@@ -30,6 +32,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
|||||||
let used = pretend::pretend_used(&cont, params.is_packed);
|
let used = pretend::pretend_used(&cont, params.is_packed);
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
#allow_deprecated
|
||||||
impl #impl_generics #ident #ty_generics #where_clause {
|
impl #impl_generics #ident #ty_generics #where_clause {
|
||||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
||||||
where
|
where
|
||||||
@@ -43,6 +46,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
|||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
#allow_deprecated
|
||||||
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
||||||
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#![deny(deprecated)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// deprecated enum
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[deprecated]
|
||||||
|
enum E1 {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deprecated struct
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[deprecated]
|
||||||
|
struct S1 {
|
||||||
|
a: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deprecated enum variant
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
enum E2 {
|
||||||
|
A,
|
||||||
|
#[deprecated]
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deprecated struct field
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct S2 {
|
||||||
|
#[deprecated]
|
||||||
|
a: bool,
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#![deny(deprecated)]
|
||||||
|
|
||||||
|
use serde::Deserializer;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Struct {
|
||||||
|
#[serde(deserialize_with = "deprecated_with")]
|
||||||
|
pub field: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
fn deprecated_with<'de, D>(_deserializer: D) -> Result<i32, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
error: use of deprecated function `deprecated_with`
|
||||||
|
--> tests/ui/deprecated/deprecated_de_with.rs:8:32
|
||||||
|
|
|
||||||
|
8 | #[serde(deserialize_with = "deprecated_with")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> tests/ui/deprecated/deprecated_de_with.rs:1:9
|
||||||
|
|
|
||||||
|
1 | #![deny(deprecated)]
|
||||||
|
| ^^^^^^^^^^
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#![deny(deprecated)]
|
||||||
|
|
||||||
|
use serde::Serializer;
|
||||||
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Struct {
|
||||||
|
#[serde(serialize_with = "deprecated_with")]
|
||||||
|
pub field: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
fn deprecated_with<S>(_field: &i32, _serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
error: use of deprecated function `deprecated_with`
|
||||||
|
--> tests/ui/deprecated/deprecated_ser_with.rs:8:30
|
||||||
|
|
|
||||||
|
8 | #[serde(serialize_with = "deprecated_with")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> tests/ui/deprecated/deprecated_ser_with.rs:1:9
|
||||||
|
|
|
||||||
|
1 | #![deny(deprecated)]
|
||||||
|
| ^^^^^^^^^^
|
||||||
Reference in New Issue
Block a user