Merge a docblock `@deprecated` message with a `#[Deprecated]` attribute. The docblock tag takes priority (it is author-written and often more specific). When the docblock has no `@deprecated` tag, falls back to the `#[Deprecated]` attribute if present. Version-aware suppression:** when the `#[Deprecated]` attribute has a `since` field and the target PHP version (from `DocblockCtx`) is older tha
(
docblock_msg: Option<String>,
attribute_lists: &Sequence<'_, attribute::AttributeList<'_>>,
doc_ctx: Option<&DocblockCtx<'_>>,
)
| 420 | /// returned for the message. Docblock `@deprecated` tags have no |
| 421 | /// structured `since` data and are always honoured. |
| 422 | pub(crate) fn merge_deprecation_info( |
| 423 | docblock_msg: Option<String>, |
| 424 | attribute_lists: &Sequence<'_, attribute::AttributeList<'_>>, |
| 425 | doc_ctx: Option<&DocblockCtx<'_>>, |
| 426 | ) -> DeprecationInfo { |
| 427 | // Docblock @deprecated always wins — it has no `since` field so |
| 428 | // version-aware suppression does not apply. |
| 429 | if docblock_msg.is_some() { |
| 430 | return DeprecationInfo { |
| 431 | message: docblock_msg, |
| 432 | replacement: None, |
| 433 | }; |
| 434 | } |
| 435 | |
| 436 | let Some(ctx) = doc_ctx else { |
| 437 | return DeprecationInfo { |
| 438 | message: None, |
| 439 | replacement: None, |
| 440 | }; |
| 441 | }; |
| 442 | |
| 443 | let Some(attr) = extract_deprecated_attribute(attribute_lists, ctx) else { |
| 444 | return DeprecationInfo { |
| 445 | message: None, |
| 446 | replacement: None, |
| 447 | }; |
| 448 | }; |
| 449 | |
| 450 | // Version-aware suppression: if the attribute declares `since` and |
| 451 | // the project targets an older PHP version, this element is not yet |
| 452 | // deprecated from the user's perspective. |
| 453 | if let Some(since_str) = &attr.since |
| 454 | && let Some(target) = ctx.php_version |
| 455 | && let Some(since_ver) = PhpVersion::from_composer_constraint(since_str) |
| 456 | && (target.major, target.minor) < (since_ver.major, since_ver.minor) |
| 457 | { |
| 458 | return DeprecationInfo { |
| 459 | message: None, |
| 460 | replacement: None, |
| 461 | }; |
| 462 | } |
| 463 | |
| 464 | DeprecationInfo { |
| 465 | message: Some(attr.to_message()), |
| 466 | replacement: attr.replacement, |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | /// Extract `#[Deprecated]` metadata from an element's attribute lists. |
| 471 | /// |
no test coverage detected