From 2ff28159d3e9915772e65955488f447cb2b98ffa Mon Sep 17 00:00:00 2001
From: Alona Enraght-Moony <code@alona.page>
Date: Sun, 16 Mar 2025 21:09:46 +0000
Subject: [PATCH 1/3] rustdoc-json: Add tests for `#[deprecated(...)]`

---
 tests/rustdoc-json/attrs/deprecated.rs | 38 ++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 tests/rustdoc-json/attrs/deprecated.rs

diff --git a/tests/rustdoc-json/attrs/deprecated.rs b/tests/rustdoc-json/attrs/deprecated.rs
new file mode 100644
index 0000000000000..c54dca1dddfaf
--- /dev/null
+++ b/tests/rustdoc-json/attrs/deprecated.rs
@@ -0,0 +1,38 @@
+//@ is "$.index[*][?(@.name=='not')].attrs" '[]'
+//@ is "$.index[*][?(@.name=='not')].deprecation" null
+pub fn not() {}
+
+//@ is "$.index[*][?(@.name=='raw')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]'
+//@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}'
+#[deprecated]
+pub fn raw() {}
+
+//@ is "$.index[*][?(@.name=='equals_string')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"here is a reason\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}'
+#[deprecated = "here is a reason"]
+pub fn equals_string() {}
+
+//@ is "$.index[*][?(@.name=='since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"yoinks ago\")}}]\n"]'
+//@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}'
+#[deprecated(since = "yoinks ago")]
+pub fn since() {}
+
+//@ is "$.index[*][?(@.name=='note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"7\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}'
+#[deprecated(note = "7")]
+pub fn note() {}
+
+//@ is "$.index[*][?(@.name=='since_and_note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"tomorrow\"), note: \"sorry\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}'
+#[deprecated(since = "tomorrow", note = "sorry")]
+pub fn since_and_note() {}
+
+//@ is "$.index[*][?(@.name=='note_and_since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"a year from tomorrow\"), note: \"your welcome\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}'
+#[deprecated(note = "your welcome", since = "a year from tomorrow")]
+pub fn note_and_since() {}
+
+//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]'
+//@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}'
+#[deprecated()]
+pub fn neither_but_parens() {}

From a8a913dcd23c75744486773e491a18af0555cdd8 Mon Sep 17 00:00:00 2001
From: Alona Enraght-Moony <code@alona.page>
Date: Sun, 16 Mar 2025 21:15:49 +0000
Subject: [PATCH 2/3] rustdoc: Rename `Item::attributes` param to `is_json`

This makes it clearer what it's actually used for, and makes it easier
to think about modifying `Item::attributes`.
---
 src/librustdoc/clean/types.rs | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3f9023659dbac..8200fa3a35d26 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -756,12 +756,7 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    pub(crate) fn attributes(
-        &self,
-        tcx: TyCtxt<'_>,
-        cache: &Cache,
-        keep_as_is: bool,
-    ) -> Vec<String> {
+    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
         const ALLOWED_ATTRIBUTES: &[Symbol] =
             &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
 
@@ -772,7 +767,7 @@ impl Item {
             .other_attrs
             .iter()
             .filter_map(|attr| {
-                if keep_as_is {
+                if is_json {
                     Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
                 } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
                     Some(
@@ -786,7 +781,8 @@ impl Item {
                 }
             })
             .collect();
-        if !keep_as_is
+
+        if !is_json
             && let Some(def_id) = self.def_id()
             && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
         {

From 677489fb3ee6808303046c5dd1956195972c84ca Mon Sep 17 00:00:00 2001
From: Alona Enraght-Moony <code@alona.page>
Date: Sun, 16 Mar 2025 21:27:54 +0000
Subject: [PATCH 3/3] rustdoc-json: Don't also include `#[deprecated]` in
 `Item::attrs`

---
 src/librustdoc/clean/types.rs          | 11 +++++++++--
 tests/rustdoc-json/attrs/deprecated.rs | 16 ++++++++--------
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8200fa3a35d26..e6f88128a7006 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,7 +5,7 @@ use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
 use rustc_abi::{ExternAbi, VariantIdx};
-use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince};
+use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -768,7 +768,13 @@ impl Item {
             .iter()
             .filter_map(|attr| {
                 if is_json {
-                    Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
+                    if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) {
+                        // rustdoc-json stores this in `Item::deprecation`, so we
+                        // don't want it it `Item::attrs`.
+                        None
+                    } else {
+                        Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
+                    }
                 } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
                     Some(
                         rustc_hir_pretty::attribute_to_string(&tcx, attr)
@@ -782,6 +788,7 @@ impl Item {
             })
             .collect();
 
+        // Add #[repr(...)]
         if !is_json
             && let Some(def_id) = self.def_id()
             && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
diff --git a/tests/rustdoc-json/attrs/deprecated.rs b/tests/rustdoc-json/attrs/deprecated.rs
index c54dca1dddfaf..5cde7af841f72 100644
--- a/tests/rustdoc-json/attrs/deprecated.rs
+++ b/tests/rustdoc-json/attrs/deprecated.rs
@@ -1,38 +1,38 @@
-//@ is "$.index[*][?(@.name=='not')].attrs" '[]'
+//@ is "$.index[*][?(@.name=='not')].attrs" []
 //@ is "$.index[*][?(@.name=='not')].deprecation" null
 pub fn not() {}
 
-//@ is "$.index[*][?(@.name=='raw')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]'
+//@ is "$.index[*][?(@.name=='raw')].attrs" []
 //@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}'
 #[deprecated]
 pub fn raw() {}
 
-//@ is "$.index[*][?(@.name=='equals_string')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"here is a reason\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='equals_string')].attrs" []
 //@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}'
 #[deprecated = "here is a reason"]
 pub fn equals_string() {}
 
-//@ is "$.index[*][?(@.name=='since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"yoinks ago\")}}]\n"]'
+//@ is "$.index[*][?(@.name=='since')].attrs" []
 //@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}'
 #[deprecated(since = "yoinks ago")]
 pub fn since() {}
 
-//@ is "$.index[*][?(@.name=='note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"7\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='note')].attrs" []
 //@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}'
 #[deprecated(note = "7")]
 pub fn note() {}
 
-//@ is "$.index[*][?(@.name=='since_and_note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"tomorrow\"), note: \"sorry\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='since_and_note')].attrs" []
 //@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}'
 #[deprecated(since = "tomorrow", note = "sorry")]
 pub fn since_and_note() {}
 
-//@ is "$.index[*][?(@.name=='note_and_since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"a year from tomorrow\"), note: \"your welcome\"}}]\n"]'
+//@ is "$.index[*][?(@.name=='note_and_since')].attrs" []
 //@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}'
 #[deprecated(note = "your welcome", since = "a year from tomorrow")]
 pub fn note_and_since() {}
 
-//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]'
+//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" []
 //@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}'
 #[deprecated()]
 pub fn neither_but_parens() {}