1use crate::internals::ast::{Container, Data, Field, Style};
2use crate::internals::attr::{Default, Identifier, TagType};
3use crate::internals::{ungroup, Ctxt, Derive};
4use syn::{Member, Type};
5
6// Cross-cutting checks that require looking at more than a single attrs object.
7// Simpler checks should happen when parsing and building the attrs.
8pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
9 check_default_on_tuple(cx, cont);
10 check_remote_generic(cx, cont);
11 check_getter(cx, cont);
12 check_flatten(cx, cont);
13 check_identifier(cx, cont);
14 check_variant_skip_attrs(cx, cont);
15 check_internal_tag_field_name_conflict(cx, cont);
16 check_adjacent_tag_conflict(cx, cont);
17 check_transparent(cx, cont, derive);
18 check_from_and_try_from(cx, cont);
19}
20
21// If some field of a tuple struct is marked #[serde(default)] then all fields
22// after it must also be marked with that attribute, or the struct must have a
23// container-level serde(default) attribute. A field's default value is only
24// used for tuple fields if the sequence is exhausted at that point; that means
25// all subsequent fields will fail to deserialize if they don't have their own
26// default.
27fn check_default_on_tuple(cx: &Ctxt, cont: &Container) {
28 if let Default::None = cont.attrs.default() {
29 if let Data::Struct(Style::Tuple, fields) = &cont.data {
30 let mut first_default_index = None;
31 for (i, field) in fields.iter().enumerate() {
32 // Skipped fields automatically get the #[serde(default)]
33 // attribute. We are interested only on non-skipped fields here.
34 if field.attrs.skip_deserializing() {
35 continue;
36 }
37 if let Default::None = field.attrs.default() {
38 if let Some(first) = first_default_index {
39 cx.error_spanned_by(
40 field.ty,
41 format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
42 );
43 }
44 continue;
45 }
46 if first_default_index.is_none() {
47 first_default_index = Some(i);
48 }
49 }
50 }
51 }
52}
53
54// Remote derive definition type must have either all of the generics of the
55// remote type:
56//
57// #[serde(remote = "Generic")]
58// struct Generic<T> {…}
59//
60// or none of them, i.e. defining impls for one concrete instantiation of the
61// remote type only:
62//
63// #[serde(remote = "Generic<T>")]
64// struct ConcreteDef {…}
65//
66fn check_remote_generic(cx: &Ctxt, cont: &Container) {
67 if let Some(remote: &Path) = cont.attrs.remote() {
68 let local_has_generic: bool = !cont.generics.params.is_empty();
69 let remote_has_generic: bool = !remote.segments.last().unwrap().arguments.is_none();
70 if local_has_generic && remote_has_generic {
71 cx.error_spanned_by(obj:remote, msg:"remove generic parameters from this path");
72 }
73 }
74}
75
76// Getters are only allowed inside structs (not enums) with the `remote`
77// attribute.
78fn check_getter(cx: &Ctxt, cont: &Container) {
79 match cont.data {
80 Data::Enum(_) => {
81 if cont.data.has_getter() {
82 cx.error_spanned_by(
83 obj:cont.original,
84 msg:"#[serde(getter = \"...\")] is not allowed in an enum",
85 );
86 }
87 }
88 Data::Struct(_, _) => {
89 if cont.data.has_getter() && cont.attrs.remote().is_none() {
90 cx.error_spanned_by(
91 obj:cont.original,
92 msg:"#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]",
93 );
94 }
95 }
96 }
97}
98
99// Flattening has some restrictions we can test.
100fn check_flatten(cx: &Ctxt, cont: &Container) {
101 match &cont.data {
102 Data::Enum(variants: &Vec>) => {
103 for variant: &Variant<'_> in variants {
104 for field: &Field<'_> in &variant.fields {
105 check_flatten_field(cx, variant.style, field);
106 }
107 }
108 }
109 Data::Struct(style: &Style, fields: &Vec>) => {
110 for field: &Field<'_> in fields {
111 check_flatten_field(cx, *style, field);
112 }
113 }
114 }
115}
116
117fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
118 if !field.attrs.flatten() {
119 return;
120 }
121 match style {
122 Style::Tuple => {
123 cx.error_spanned_by(
124 obj:field.original,
125 msg:"#[serde(flatten)] cannot be used on tuple structs",
126 );
127 }
128 Style::Newtype => {
129 cx.error_spanned_by(
130 obj:field.original,
131 msg:"#[serde(flatten)] cannot be used on newtype structs",
132 );
133 }
134 _ => {}
135 }
136}
137
138// The `other` attribute must be used at most once and it must be the last
139// variant of an enum.
140//
141// Inside a `variant_identifier` all variants must be unit variants. Inside a
142// `field_identifier` all but possibly one variant must be unit variants. The
143// last variant may be a newtype variant which is an implicit "other" case.
144fn check_identifier(cx: &Ctxt, cont: &Container) {
145 let variants = match &cont.data {
146 Data::Enum(variants) => variants,
147 Data::Struct(_, _) => return,
148 };
149
150 for (i, variant) in variants.iter().enumerate() {
151 match (
152 variant.style,
153 cont.attrs.identifier(),
154 variant.attrs.other(),
155 cont.attrs.tag(),
156 ) {
157 // The `other` attribute may not be used in a variant_identifier.
158 (_, Identifier::Variant, true, _) => {
159 cx.error_spanned_by(
160 variant.original,
161 "#[serde(other)] may not be used on a variant identifier",
162 );
163 }
164
165 // Variant with `other` attribute cannot appear in untagged enum
166 (_, Identifier::No, true, &TagType::None) => {
167 cx.error_spanned_by(
168 variant.original,
169 "#[serde(other)] cannot appear on untagged enum",
170 );
171 }
172
173 // Variant with `other` attribute must be the last one.
174 (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
175 if i < variants.len() - 1 {
176 cx.error_spanned_by(
177 variant.original,
178 "#[serde(other)] must be on the last variant",
179 );
180 }
181 }
182
183 // Variant with `other` attribute must be a unit variant.
184 (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
185 cx.error_spanned_by(
186 variant.original,
187 "#[serde(other)] must be on a unit variant",
188 );
189 }
190
191 // Any sort of variant is allowed if this is not an identifier.
192 (_, Identifier::No, false, _) => {}
193
194 // Unit variant without `other` attribute is always fine.
195 (Style::Unit, _, false, _) => {}
196
197 // The last field is allowed to be a newtype catch-all.
198 (Style::Newtype, Identifier::Field, false, _) => {
199 if i < variants.len() - 1 {
200 cx.error_spanned_by(
201 variant.original,
202 format!("`{}` must be the last variant", variant.ident),
203 );
204 }
205 }
206
207 (_, Identifier::Field, false, _) => {
208 cx.error_spanned_by(
209 variant.original,
210 "#[serde(field_identifier)] may only contain unit variants",
211 );
212 }
213
214 (_, Identifier::Variant, false, _) => {
215 cx.error_spanned_by(
216 variant.original,
217 "#[serde(variant_identifier)] may only contain unit variants",
218 );
219 }
220 }
221 }
222}
223
224// Skip-(de)serializing attributes are not allowed on variants marked
225// (de)serialize_with.
226fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
227 let variants = match &cont.data {
228 Data::Enum(variants) => variants,
229 Data::Struct(_, _) => return,
230 };
231
232 for variant in variants {
233 if variant.attrs.serialize_with().is_some() {
234 if variant.attrs.skip_serializing() {
235 cx.error_spanned_by(
236 variant.original,
237 format!(
238 "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]",
239 variant.ident
240 ),
241 );
242 }
243
244 for field in &variant.fields {
245 let member = member_message(&field.member);
246
247 if field.attrs.skip_serializing() {
248 cx.error_spanned_by(
249 variant.original,
250 format!(
251 "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]",
252 variant.ident, member
253 ),
254 );
255 }
256
257 if field.attrs.skip_serializing_if().is_some() {
258 cx.error_spanned_by(
259 variant.original,
260 format!(
261 "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]",
262 variant.ident, member
263 ),
264 );
265 }
266 }
267 }
268
269 if variant.attrs.deserialize_with().is_some() {
270 if variant.attrs.skip_deserializing() {
271 cx.error_spanned_by(
272 variant.original,
273 format!(
274 "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]",
275 variant.ident
276 ),
277 );
278 }
279
280 for field in &variant.fields {
281 if field.attrs.skip_deserializing() {
282 let member = member_message(&field.member);
283
284 cx.error_spanned_by(
285 variant.original,
286 format!(
287 "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]",
288 variant.ident, member
289 ),
290 );
291 }
292 }
293 }
294 }
295}
296
297// The tag of an internally-tagged struct variant must not be the same as either
298// one of its fields, as this would result in duplicate keys in the serialized
299// output and/or ambiguity in the to-be-deserialized input.
300fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
301 let variants = match &cont.data {
302 Data::Enum(variants) => variants,
303 Data::Struct(_, _) => return,
304 };
305
306 let tag = match cont.attrs.tag() {
307 TagType::Internal { tag } => tag.as_str(),
308 TagType::External | TagType::Adjacent { .. } | TagType::None => return,
309 };
310
311 let diagnose_conflict = || {
312 cx.error_spanned_by(
313 cont.original,
314 format!("variant field name `{}` conflicts with internal tag", tag),
315 );
316 };
317
318 for variant in variants {
319 match variant.style {
320 Style::Struct => {
321 for field in &variant.fields {
322 let check_ser =
323 !(field.attrs.skip_serializing() || variant.attrs.skip_serializing());
324 let check_de =
325 !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing());
326 let name = field.attrs.name();
327 let ser_name = name.serialize_name();
328
329 if check_ser && ser_name == tag {
330 diagnose_conflict();
331 return;
332 }
333
334 for de_name in field.attrs.aliases() {
335 if check_de && de_name == tag {
336 diagnose_conflict();
337 return;
338 }
339 }
340 }
341 }
342 Style::Unit | Style::Newtype | Style::Tuple => {}
343 }
344 }
345}
346
347// In the case of adjacently-tagged enums, the type and the contents tag must
348// differ, for the same reason.
349fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
350 let (type_tag: &String, content_tag: &String) = match cont.attrs.tag() {
351 TagType::Adjacent { tag: &String, content: &String } => (tag, content),
352 TagType::Internal { .. } | TagType::External | TagType::None => return,
353 };
354
355 if type_tag == content_tag {
356 cx.error_spanned_by(
357 obj:cont.original,
358 msg:format!(
359 "enum tags `{}` for type and content conflict with each other",
360 type_tag
361 ),
362 );
363 }
364}
365
366// Enums and unit structs cannot be transparent.
367fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
368 if !cont.attrs.transparent() {
369 return;
370 }
371
372 if cont.attrs.type_from().is_some() {
373 cx.error_spanned_by(
374 cont.original,
375 "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]",
376 );
377 }
378
379 if cont.attrs.type_try_from().is_some() {
380 cx.error_spanned_by(
381 cont.original,
382 "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]",
383 );
384 }
385
386 if cont.attrs.type_into().is_some() {
387 cx.error_spanned_by(
388 cont.original,
389 "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]",
390 );
391 }
392
393 let fields = match &mut cont.data {
394 Data::Enum(_) => {
395 cx.error_spanned_by(
396 cont.original,
397 "#[serde(transparent)] is not allowed on an enum",
398 );
399 return;
400 }
401 Data::Struct(Style::Unit, _) => {
402 cx.error_spanned_by(
403 cont.original,
404 "#[serde(transparent)] is not allowed on a unit struct",
405 );
406 return;
407 }
408 Data::Struct(_, fields) => fields,
409 };
410
411 let mut transparent_field = None;
412
413 for field in fields {
414 if allow_transparent(field, derive) {
415 if transparent_field.is_some() {
416 cx.error_spanned_by(
417 cont.original,
418 "#[serde(transparent)] requires struct to have at most one transparent field",
419 );
420 return;
421 }
422 transparent_field = Some(field);
423 }
424 }
425
426 match transparent_field {
427 Some(transparent_field) => transparent_field.attrs.mark_transparent(),
428 None => match derive {
429 Derive::Serialize => {
430 cx.error_spanned_by(
431 cont.original,
432 "#[serde(transparent)] requires at least one field that is not skipped",
433 );
434 }
435 Derive::Deserialize => {
436 cx.error_spanned_by(
437 cont.original,
438 "#[serde(transparent)] requires at least one field that is neither skipped nor has a default",
439 );
440 }
441 },
442 }
443}
444
445fn member_message(member: &Member) -> String {
446 match member {
447 Member::Named(ident: &Ident) => format!("`{}`", ident),
448 Member::Unnamed(i: &Index) => format!("#{}", i.index),
449 }
450}
451
452fn allow_transparent(field: &Field, derive: Derive) -> bool {
453 if let Type::Path(ty: &TypePath) = ungroup(field.ty) {
454 if let Some(seg: &PathSegment) = ty.path.segments.last() {
455 if seg.ident == "PhantomData" {
456 return false;
457 }
458 }
459 }
460
461 match derive {
462 Derive::Serialize => !field.attrs.skip_serializing(),
463 Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
464 }
465}
466
467fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
468 if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() {
469 cx.error_spanned_by(
470 obj:cont.original,
471 msg:"#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other",
472 );
473 }
474}
475