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) = cont.attrs.remote() { 68 let local_has_generic = !cont.generics.params.is_empty(); 69 let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); 70 if local_has_generic && remote_has_generic { 71 cx.error_spanned_by(remote, "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 cont.original, 84 "#[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 cont.original, 92 "#[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) => { 103 for variant in variants { 104 for field in &variant.fields { 105 check_flatten_field(cx, variant.style, field); 106 } 107 } 108 } 109 Data::Struct(style, fields) => { 110 for 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 field.original, 125 "#[serde(flatten)] cannot be used on tuple structs", 126 ); 127 } 128 Style::Newtype => { 129 cx.error_spanned_by( 130 field.original, 131 "#[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 if variant.attrs.untagged() { 322 continue; 323 } 324 for field in &variant.fields { 325 let check_ser = 326 !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); 327 let check_de = 328 !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); 329 let name = field.attrs.name(); 330 let ser_name = name.serialize_name(); 331 332 if check_ser && ser_name == tag { 333 diagnose_conflict(); 334 return; 335 } 336 337 for de_name in field.attrs.aliases() { 338 if check_de && de_name == tag { 339 diagnose_conflict(); 340 return; 341 } 342 } 343 } 344 } 345 Style::Unit | Style::Newtype | Style::Tuple => {} 346 } 347 } 348} 349 350// In the case of adjacently-tagged enums, the type and the contents tag must 351// differ, for the same reason. 352fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { 353 let (type_tag, content_tag) = match cont.attrs.tag() { 354 TagType::Adjacent { tag, content } => (tag, content), 355 TagType::Internal { .. } | TagType::External | TagType::None => return, 356 }; 357 358 if type_tag == content_tag { 359 cx.error_spanned_by( 360 cont.original, 361 format!( 362 "enum tags `{}` for type and content conflict with each other", 363 type_tag 364 ), 365 ); 366 } 367} 368 369// Enums and unit structs cannot be transparent. 370fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { 371 if !cont.attrs.transparent() { 372 return; 373 } 374 375 if cont.attrs.type_from().is_some() { 376 cx.error_spanned_by( 377 cont.original, 378 "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", 379 ); 380 } 381 382 if cont.attrs.type_try_from().is_some() { 383 cx.error_spanned_by( 384 cont.original, 385 "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", 386 ); 387 } 388 389 if cont.attrs.type_into().is_some() { 390 cx.error_spanned_by( 391 cont.original, 392 "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", 393 ); 394 } 395 396 let fields = match &mut cont.data { 397 Data::Enum(_) => { 398 cx.error_spanned_by( 399 cont.original, 400 "#[serde(transparent)] is not allowed on an enum", 401 ); 402 return; 403 } 404 Data::Struct(Style::Unit, _) => { 405 cx.error_spanned_by( 406 cont.original, 407 "#[serde(transparent)] is not allowed on a unit struct", 408 ); 409 return; 410 } 411 Data::Struct(_, fields) => fields, 412 }; 413 414 let mut transparent_field = None; 415 416 for field in fields { 417 if allow_transparent(field, derive) { 418 if transparent_field.is_some() { 419 cx.error_spanned_by( 420 cont.original, 421 "#[serde(transparent)] requires struct to have at most one transparent field", 422 ); 423 return; 424 } 425 transparent_field = Some(field); 426 } 427 } 428 429 match transparent_field { 430 Some(transparent_field) => transparent_field.attrs.mark_transparent(), 431 None => match derive { 432 Derive::Serialize => { 433 cx.error_spanned_by( 434 cont.original, 435 "#[serde(transparent)] requires at least one field that is not skipped", 436 ); 437 } 438 Derive::Deserialize => { 439 cx.error_spanned_by( 440 cont.original, 441 "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", 442 ); 443 } 444 }, 445 } 446} 447 448fn member_message(member: &Member) -> String { 449 match member { 450 Member::Named(ident) => format!("`{}`", ident), 451 Member::Unnamed(i) => format!("#{}", i.index), 452 } 453} 454 455fn allow_transparent(field: &Field, derive: Derive) -> bool { 456 if let Type::Path(ty) = ungroup(field.ty) { 457 if let Some(seg) = ty.path.segments.last() { 458 if seg.ident == "PhantomData" { 459 return false; 460 } 461 } 462 } 463 464 match derive { 465 Derive::Serialize => !field.attrs.skip_serializing(), 466 Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), 467 } 468} 469 470fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { 471 if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { 472 cx.error_spanned_by( 473 cont.original, 474 "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", 475 ); 476 } 477} 478