Skip to content

Commit 7f1e697

Browse files
authored
Merge pull request #2855 from dtolnay/namespan
Produce unreachable_patterns warning when deserialization names collide
2 parents 60ac737 + 373edcd commit 7f1e697

File tree

6 files changed

+174
-94
lines changed

6 files changed

+174
-94
lines changed

serde_derive/src/de.rs

+3-2
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::name::Name;
34
use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
45
use crate::{bound, dummy, pretend, this};
56
use proc_macro2::{Literal, Span, TokenStream};
@@ -2002,7 +2003,7 @@ fn deserialize_untagged_newtype_variant(
20022003

20032004
struct FieldWithAliases<'a> {
20042005
ident: Ident,
2005-
aliases: &'a BTreeSet<String>,
2006+
aliases: &'a BTreeSet<Name>,
20062007
}
20072008

20082009
fn deserialize_generated_identifier(
@@ -2224,7 +2225,7 @@ fn deserialize_identifier(
22242225
let aliases = field
22252226
.aliases
22262227
.iter()
2227-
.map(|alias| Literal::byte_string(alias.as_bytes()));
2228+
.map(|alias| Literal::byte_string(alias.value.as_bytes()));
22282229
quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident))
22292230
});
22302231

serde_derive/src/internals/attr.rs

+48-84
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::internals::name::{MultiName, Name};
12
use crate::internals::symbol::*;
23
use crate::internals::{ungroup, Ctxt};
34
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
@@ -21,7 +22,7 @@ use syn::{parse_quote, token, Ident, Lifetime, Token};
2122

2223
pub use crate::internals::case::RenameRule;
2324

24-
struct Attr<'c, T> {
25+
pub(crate) struct Attr<'c, T> {
2526
cx: &'c Ctxt,
2627
name: Symbol,
2728
tokens: TokenStream,
@@ -62,7 +63,7 @@ impl<'c, T> Attr<'c, T> {
6263
}
6364
}
6465

65-
fn get(self) -> Option<T> {
66+
pub(crate) fn get(self) -> Option<T> {
6667
self.value
6768
}
6869

@@ -90,7 +91,7 @@ impl<'c> BoolAttr<'c> {
9091
}
9192
}
9293

93-
struct VecAttr<'c, T> {
94+
pub(crate) struct VecAttr<'c, T> {
9495
cx: &'c Ctxt,
9596
name: Symbol,
9697
first_dup_tokens: TokenStream,
@@ -125,63 +126,13 @@ impl<'c, T> VecAttr<'c, T> {
125126
}
126127
}
127128

128-
fn get(self) -> Vec<T> {
129+
pub(crate) fn get(self) -> Vec<T> {
129130
self.values
130131
}
131132
}
132133

133-
pub struct Name {
134-
serialize: String,
135-
serialize_renamed: bool,
136-
deserialize: String,
137-
deserialize_renamed: bool,
138-
deserialize_aliases: BTreeSet<String>,
139-
}
140-
141-
fn unraw(ident: &Ident) -> String {
142-
ident.to_string().trim_start_matches("r#").to_owned()
143-
}
144-
145-
impl Name {
146-
fn from_attrs(
147-
source_name: String,
148-
ser_name: Attr<String>,
149-
de_name: Attr<String>,
150-
de_aliases: Option<VecAttr<String>>,
151-
) -> Name {
152-
let mut alias_set = BTreeSet::new();
153-
if let Some(de_aliases) = de_aliases {
154-
for alias_name in de_aliases.get() {
155-
alias_set.insert(alias_name);
156-
}
157-
}
158-
159-
let ser_name = ser_name.get();
160-
let ser_renamed = ser_name.is_some();
161-
let de_name = de_name.get();
162-
let de_renamed = de_name.is_some();
163-
Name {
164-
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
165-
serialize_renamed: ser_renamed,
166-
deserialize: de_name.unwrap_or(source_name),
167-
deserialize_renamed: de_renamed,
168-
deserialize_aliases: alias_set,
169-
}
170-
}
171-
172-
/// Return the container name for the container when serializing.
173-
pub fn serialize_name(&self) -> &str {
174-
&self.serialize
175-
}
176-
177-
/// Return the container name for the container when deserializing.
178-
pub fn deserialize_name(&self) -> &str {
179-
&self.deserialize
180-
}
181-
182-
fn deserialize_aliases(&self) -> &BTreeSet<String> {
183-
&self.deserialize_aliases
184-
}
134+
fn unraw(ident: &Ident) -> Ident {
135+
Ident::new(ident.to_string().trim_start_matches("r#"), ident.span())
185136
}
186137

187138
#[derive(Copy, Clone)]
@@ -203,7 +154,7 @@ impl RenameAllRules {
203154

204155
/// Represents struct or enum attribute information.
205156
pub struct Container {
206-
name: Name,
157+
name: MultiName,
207158
transparent: bool,
208159
deny_unknown_fields: bool,
209160
default: Default,
@@ -327,8 +278,8 @@ impl Container {
327278
// #[serde(rename = "foo")]
328279
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
329280
let (ser, de) = get_renames(cx, RENAME, &meta)?;
330-
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
331-
de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value));
281+
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
282+
de_name.set_opt(&meta.path, de.as_ref().map(Name::from));
332283
} else if meta.path == RENAME_ALL {
333284
// #[serde(rename_all = "foo")]
334285
// #[serde(rename_all(serialize = "foo", deserialize = "bar"))]
@@ -567,7 +518,7 @@ impl Container {
567518
}
568519

569520
Container {
570-
name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None),
521+
name: MultiName::from_attrs(Name::from(&unraw(&item.ident)), ser_name, de_name, None),
571522
transparent: transparent.get(),
572523
deny_unknown_fields: deny_unknown_fields.get(),
573524
default: default.get().unwrap_or(Default::None),
@@ -594,7 +545,7 @@ impl Container {
594545
}
595546
}
596547

597-
pub fn name(&self) -> &Name {
548+
pub fn name(&self) -> &MultiName {
598549
&self.name
599550
}
600551

@@ -781,7 +732,7 @@ fn decide_identifier(
781732

782733
/// Represents variant attribute information
783734
pub struct Variant {
784-
name: Name,
735+
name: MultiName,
785736
rename_all_rules: RenameAllRules,
786737
ser_bound: Option<Vec<syn::WherePredicate>>,
787738
de_bound: Option<Vec<syn::WherePredicate>>,
@@ -832,15 +783,15 @@ impl Variant {
832783
// #[serde(rename = "foo")]
833784
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
834785
let (ser, de) = get_multiple_renames(cx, &meta)?;
835-
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
786+
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
836787
for de_value in de {
837-
de_name.set_if_none(de_value.value());
838-
de_aliases.insert(&meta.path, de_value.value());
788+
de_name.set_if_none(Name::from(&de_value));
789+
de_aliases.insert(&meta.path, Name::from(&de_value));
839790
}
840791
} else if meta.path == ALIAS {
841792
// #[serde(alias = "foo")]
842793
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
843-
de_aliases.insert(&meta.path, s.value());
794+
de_aliases.insert(&meta.path, Name::from(&s));
844795
}
845796
} else if meta.path == RENAME_ALL {
846797
// #[serde(rename_all = "foo")]
@@ -947,7 +898,12 @@ impl Variant {
947898
}
948899

949900
Variant {
950-
name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)),
901+
name: MultiName::from_attrs(
902+
Name::from(&unraw(&variant.ident)),
903+
ser_name,
904+
de_name,
905+
Some(de_aliases),
906+
),
951907
rename_all_rules: RenameAllRules {
952908
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
953909
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
@@ -964,20 +920,23 @@ impl Variant {
964920
}
965921
}
966922

967-
pub fn name(&self) -> &Name {
923+
pub fn name(&self) -> &MultiName {
968924
&self.name
969925
}
970926

971-
pub fn aliases(&self) -> &BTreeSet<String> {
927+
pub fn aliases(&self) -> &BTreeSet<Name> {
972928
self.name.deserialize_aliases()
973929
}
974930

975931
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
976932
if !self.name.serialize_renamed {
977-
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
933+
self.name.serialize.value =
934+
rules.serialize.apply_to_variant(&self.name.serialize.value);
978935
}
979936
if !self.name.deserialize_renamed {
980-
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
937+
self.name.deserialize.value = rules
938+
.deserialize
939+
.apply_to_variant(&self.name.deserialize.value);
981940
}
982941
self.name
983942
.deserialize_aliases
@@ -1023,7 +982,7 @@ impl Variant {
1023982

1024983
/// Represents field attribute information
1025984
pub struct Field {
1026-
name: Name,
985+
name: MultiName,
1027986
skip_serializing: bool,
1028987
skip_deserializing: bool,
1029988
skip_serializing_if: Option<syn::ExprPath>,
@@ -1082,8 +1041,11 @@ impl Field {
10821041
let mut flatten = BoolAttr::none(cx, FLATTEN);
10831042

10841043
let ident = match &field.ident {
1085-
Some(ident) => unraw(ident),
1086-
None => index.to_string(),
1044+
Some(ident) => Name::from(&unraw(ident)),
1045+
None => Name {
1046+
value: index.to_string(),
1047+
span: Span::call_site(),
1048+
},
10871049
};
10881050

10891051
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
@@ -1119,15 +1081,15 @@ impl Field {
11191081
// #[serde(rename = "foo")]
11201082
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
11211083
let (ser, de) = get_multiple_renames(cx, &meta)?;
1122-
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
1084+
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
11231085
for de_value in de {
1124-
de_name.set_if_none(de_value.value());
1125-
de_aliases.insert(&meta.path, de_value.value());
1086+
de_name.set_if_none(Name::from(&de_value));
1087+
de_aliases.insert(&meta.path, Name::from(&de_value));
11261088
}
11271089
} else if meta.path == ALIAS {
11281090
// #[serde(alias = "foo")]
11291091
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
1130-
de_aliases.insert(&meta.path, s.value());
1092+
de_aliases.insert(&meta.path, Name::from(&s));
11311093
}
11321094
} else if meta.path == DEFAULT {
11331095
if meta.input.peek(Token![=]) {
@@ -1290,7 +1252,7 @@ impl Field {
12901252
}
12911253

12921254
Field {
1293-
name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
1255+
name: MultiName::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
12941256
skip_serializing: skip_serializing.get(),
12951257
skip_deserializing: skip_deserializing.get(),
12961258
skip_serializing_if: skip_serializing_if.get(),
@@ -1306,20 +1268,22 @@ impl Field {
13061268
}
13071269
}
13081270

1309-
pub fn name(&self) -> &Name {
1271+
pub fn name(&self) -> &MultiName {
13101272
&self.name
13111273
}
13121274

1313-
pub fn aliases(&self) -> &BTreeSet<String> {
1275+
pub fn aliases(&self) -> &BTreeSet<Name> {
13141276
self.name.deserialize_aliases()
13151277
}
13161278

13171279
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
13181280
if !self.name.serialize_renamed {
1319-
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
1281+
self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value);
13201282
}
13211283
if !self.name.deserialize_renamed {
1322-
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
1284+
self.name.deserialize.value = rules
1285+
.deserialize
1286+
.apply_to_field(&self.name.deserialize.value);
13231287
}
13241288
self.name
13251289
.deserialize_aliases
@@ -1769,7 +1733,7 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
17691733
// attribute on the field so there must be at least one borrowable lifetime.
17701734
fn borrowable_lifetimes(
17711735
cx: &Ctxt,
1772-
name: &str,
1736+
name: &Name,
17731737
field: &syn::Field,
17741738
) -> Result<BTreeSet<syn::Lifetime>, ()> {
17751739
let mut lifetimes = BTreeSet::new();

serde_derive/src/internals/check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,13 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
332332
let name = field.attrs.name();
333333
let ser_name = name.serialize_name();
334334

335-
if check_ser && ser_name == tag {
335+
if check_ser && ser_name.value == tag {
336336
diagnose_conflict();
337337
return;
338338
}
339339

340340
for de_name in field.attrs.aliases() {
341-
if check_de && de_name == tag {
341+
if check_de && de_name.value == tag {
342342
diagnose_conflict();
343343
return;
344344
}

serde_derive/src/internals/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod ast;
22
pub mod attr;
3+
pub mod name;
34

45
mod case;
56
mod check;

0 commit comments

Comments
 (0)