Skip to content

Commit f321f10

Browse files
committed
Fix rustdoc and clippy
1 parent 7e0f5b5 commit f321f10

31 files changed

+134
-121
lines changed

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ impl AttributeExt for Attribute {
11451145
}
11461146

11471147
fn is_doc_comment(&self) -> bool {
1148+
// FIXME(jdonszelmann): make the 2nd check unnecessary here
11481149
matches!(self, Attribute::Parsed(AttributeKind::DocComment { .. }))
11491150
}
11501151

src/librustdoc/clean/mod.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -2737,13 +2737,13 @@ fn add_without_unwanted_attributes<'hir>(
27372737
import_parent: Option<DefId>,
27382738
) {
27392739
for attr in new_attrs {
2740-
if matches!(attr.kind, hir::AttrKind::DocComment(..)) {
2740+
if attr.is_doc_comment() {
27412741
attrs.push((Cow::Borrowed(attr), import_parent));
27422742
continue;
27432743
}
27442744
let mut attr = attr.clone();
2745-
match attr.kind {
2746-
hir::AttrKind::Normal(ref mut normal) => {
2745+
match attr {
2746+
hir::Attribute::Unparsed(ref mut normal) => {
27472747
if let [ident] = &*normal.path.segments {
27482748
let ident = ident.name;
27492749
if ident == sym::doc {
@@ -2755,7 +2755,11 @@ fn add_without_unwanted_attributes<'hir>(
27552755
}
27562756
}
27572757
}
2758-
_ => unreachable!(),
2758+
hir::Attribute::Parsed(..) => {
2759+
if is_inline {
2760+
attrs.push((Cow::Owned(attr), import_parent));
2761+
}
2762+
}
27592763
}
27602764
}
27612765
}

src/librustdoc/clean/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl ExternalCrate {
265265
let attr_value = attr.value_str().expect("syntax should already be validated");
266266
let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
267267
span_bug!(
268-
attr.span,
268+
attr.span(),
269269
"primitive `{attr_value}` is not a member of `PrimitiveType`"
270270
);
271271
};

src/librustdoc/doctest/rust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ impl HirCollector<'_> {
123123
.iter()
124124
.find(|attr| attr.doc_str().is_some())
125125
.map(|attr| {
126-
attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span)
126+
attr.span().ctxt().outer_expn().expansion_cause().unwrap_or(attr.span())
127127
})
128128
.unwrap_or(DUMMY_SP)
129129
};

src/rustdoc-json-types/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
3030
/// This integer is incremented with every breaking change to the API,
3131
/// and is returned along with the JSON blob as [`Crate::format_version`].
3232
/// Consuming code should assert that this value matches the format version(s) that it supports.
33-
pub const FORMAT_VERSION: u32 = 39;
33+
pub const FORMAT_VERSION: u32 = 40;
3434

3535
/// The root of the emitted JSON blob.
3636
///
@@ -120,7 +120,9 @@ pub struct Item {
120120
pub docs: Option<String>,
121121
/// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
122122
pub links: HashMap<String, Id>,
123-
/// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
123+
/// Stringified versions of parsed attributes on this item.
124+
/// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`).
125+
/// Equivalent to the hir pretty-printing of attributes.
124126
pub attrs: Vec<String>,
125127
/// Information about the item’s deprecation, if present.
126128
pub deprecation: Option<Deprecation>,

src/tools/clippy/clippy_lints/src/attrs/inline_always.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att
2020
span_lint(
2121
cx,
2222
INLINE_ALWAYS,
23-
attr.span,
23+
attr.span(),
2424
format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
2525
);
2626
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr};
12
use rustc_hir::Attribute;
23
use rustc_lint::LateContext;
3-
use rustc_span::{Span, sym};
4+
use rustc_span::Span;
45

56
use clippy_utils::diagnostics::span_lint_and_then;
67
use clippy_utils::msrvs;
@@ -14,30 +15,21 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute],
1415
}
1516

1617
fn check_packed(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
17-
if let Some(items) = attrs.iter().find_map(|attr| {
18-
if attr.ident().is_some_and(|ident| matches!(ident.name, sym::repr)) {
19-
attr.meta_item_list()
20-
} else {
21-
None
18+
if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
19+
let packed_span = reprs.iter().find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))).map(|(_, s)| *s);
20+
21+
if let Some(packed_span) = packed_span && !reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC || *x == ReprAttr::ReprRust) {
22+
span_lint_and_then(
23+
cx,
24+
REPR_PACKED_WITHOUT_ABI,
25+
item_span,
26+
"item uses `packed` representation without ABI-qualification",
27+
|diag| {
28+
diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI")
29+
.help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
30+
.span_label(packed_span, "`packed` representation set here");
31+
},
32+
);
2233
}
23-
}) && let Some(packed) = items
24-
.iter()
25-
.find(|item| item.ident().is_some_and(|ident| matches!(ident.name, sym::packed)))
26-
&& !items.iter().any(|item| {
27-
item.ident()
28-
.is_some_and(|ident| matches!(ident.name, sym::C | sym::Rust))
29-
})
30-
{
31-
span_lint_and_then(
32-
cx,
33-
REPR_PACKED_WITHOUT_ABI,
34-
item_span,
35-
"item uses `packed` representation without ABI-qualification",
36-
|diag| {
37-
diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI")
38-
.help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
39-
.span_label(packed.span(), "`packed` representation set here");
40-
},
41-
);
4234
}
4335
}

src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(super) fn check(
1515
) {
1616
if cfg_attr.has_name(sym::clippy)
1717
&& let Some(ident) = behind_cfg_attr.ident()
18-
&& Level::from_symbol(ident.name, Some(attr.id)).is_some()
18+
&& Level::from_symbol(ident.name, || Some(attr.id)).is_some()
1919
&& let Some(items) = behind_cfg_attr.meta_item_list()
2020
{
2121
let nb_items = items.len();

src/tools/clippy/clippy_lints/src/attrs/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool {
1717
}
1818

1919
pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
20-
Level::from_symbol(symbol, Some(attr_id)).is_some()
20+
Level::from_symbol(symbol, || Some(attr_id)).is_some()
2121
}
2222

2323
pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {

src/tools/clippy/clippy_lints/src/default_union_representation.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2+
use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr};
23
use rustc_hir::{HirId, Item, ItemKind};
34
use rustc_lint::{LateContext, LateLintPass};
45
use rustc_middle::ty::layout::LayoutOf;
56
use rustc_middle::ty::{self, FieldDef};
67
use rustc_session::declare_lint_pass;
7-
use rustc_span::sym;
88

99
declare_clippy_lint! {
1010
/// ### What it does
@@ -97,16 +97,7 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR
9797
}
9898

9999
fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
100-
cx.tcx.hir().attrs(hir_id).iter().any(|attr| {
101-
if attr.has_name(sym::repr) {
102-
if let Some(items) = attr.meta_item_list() {
103-
for item in items {
104-
if item.is_word() && matches!(item.name_or_empty(), sym::C) {
105-
return true;
106-
}
107-
}
108-
}
109-
}
110-
false
111-
})
100+
let attrs = cx.tcx.hir().attrs(hir_id);
101+
102+
find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC))
112103
}

src/tools/clippy/clippy_lints/src/disallowed_macros.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
use clippy_config::Conf;
23
use clippy_config::types::create_disallowed_map;
34
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};

src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet_opt;
3-
use rustc_ast::AttrStyle;
43
use rustc_errors::Applicability;
5-
use rustc_hir::{AttrArgs, AttrKind, Attribute};
6-
use rustc_lint::LateContext;
4+
use rustc_lint::EarlyContext;
5+
use rustc_ast::{Attribute, AttrKind, AttrArgs, AttrStyle};
76

87
use super::DOC_INCLUDE_WITHOUT_CFG;
98

10-
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
9+
pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
1110
for attr in attrs {
1211
if !attr.span.from_expansion()
1312
&& let AttrKind::Normal(ref item) = attr.kind
1413
&& attr.doc_str().is_some()
15-
&& let AttrArgs::Eq { expr: meta, .. } = &item.args
14+
&& let AttrArgs::Eq { expr: meta, .. } = &item.item.args
1615
&& !attr.span.contains(meta.span)
1716
// Since the `include_str` is already expanded at this point, we can only take the
1817
// whole attribute snippet and then modify for our suggestion.

src/tools/clippy/clippy_lints/src/doc/mod.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashSet;
2020
use rustc_errors::Applicability;
2121
use rustc_hir::intravisit::{self, Visitor};
2222
use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
23-
use rustc_lint::{LateContext, LateLintPass, LintContext};
23+
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
2424
use rustc_middle::hir::nested_filter;
2525
use rustc_middle::ty;
2626
use rustc_resolve::rustdoc::{
@@ -577,6 +577,13 @@ impl_lint_pass!(Documentation => [
577577
DOC_INCLUDE_WITHOUT_CFG,
578578
]);
579579

580+
581+
impl EarlyLintPass for Documentation {
582+
fn check_attributes(&mut self, cx: &EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) {
583+
include_in_doc_without_cfg::check(cx, attrs);
584+
}
585+
}
586+
580587
impl<'tcx> LateLintPass<'tcx> for Documentation {
581588
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
582589
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
@@ -704,14 +711,13 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
704711
Some(("fake".into(), "fake".into()))
705712
}
706713

707-
include_in_doc_without_cfg::check(cx, attrs);
708714
if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) {
709715
return None;
710716
}
711717

712718
let (fragments, _) = attrs_to_doc_fragments(
713719
attrs.iter().filter_map(|attr| {
714-
if attr.span.in_external_macro(cx.sess().source_map()) {
720+
if !attr.doc_str_and_comment_kind().is_some() || attr.span().in_external_macro(cx.sess().source_map()) {
715721
None
716722
} else {
717723
Some((attr, None))

src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_ast::AttrStyle;
33
use rustc_ast::token::CommentKind;
44
use rustc_errors::Applicability;
55
use rustc_hir::Attribute;
6+
use rustc_attr_parsing::AttributeKind;
67
use rustc_lint::LateContext;
78
use rustc_span::Span;
89

@@ -36,15 +37,14 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
3637
attrs
3738
.iter()
3839
.filter_map(|attr| {
39-
if let Some((sym, com_kind)) = attr.doc_str_and_comment_kind()
40-
&& let AttrStyle::Outer = attr.style
41-
&& let Some(com) = sym.as_str().strip_prefix('!')
40+
if let Attribute::Parsed(AttributeKind::DocComment{ style: AttrStyle::Outer, kind, comment, ..}) = attr
41+
&& let Some(com) = comment.as_str().strip_prefix('!')
4242
{
43-
let sugg = match com_kind {
43+
let sugg = match kind {
4444
CommentKind::Line => format!("//!{com}"),
4545
CommentKind::Block => format!("/*!{com}*/"),
4646
};
47-
Some((attr.span, sugg))
47+
Some((attr.span(), sugg))
4848
} else {
4949
None
5050
}

src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_errors::Applicability;
22
use rustc_hir::{Attribute, Item, ItemKind};
3+
use rustc_attr_parsing::AttributeKind;
34
use rustc_lint::LateContext;
45

56
use clippy_utils::diagnostics::span_lint_and_then;
@@ -43,9 +44,9 @@ pub(super) fn check(
4344
let mut should_suggest_empty_doc = false;
4445

4546
for attr in attrs {
46-
if let Some(doc) = attr.doc_str() {
47-
spans.push(attr.span);
48-
let doc = doc.as_str();
47+
if let Attribute::Parsed(AttributeKind::DocComment {span, comment, ..}) = attr {
48+
spans.push(span);
49+
let doc = comment.as_str();
4950
let doc = doc.trim();
5051
if spans.len() == 1 {
5152
// We make this suggestion only if the first doc line ends with a punctuation
@@ -78,7 +79,7 @@ pub(super) fn check(
7879
&& let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi())
7980
&& let Some(snippet) = snippet_opt(cx, new_span)
8081
{
81-
let Some(first) = snippet_opt(cx, first_span) else {
82+
let Some(first) = snippet_opt(cx, *first_span) else {
8283
return;
8384
};
8485
let Some(comment_form) = first.get(..3) else {

src/tools/clippy/clippy_lints/src/four_forward_slashes.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
4646
.hir()
4747
.attrs(item.hir_id())
4848
.iter()
49-
.fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
49+
.filter(|i| i.is_doc_comment())
50+
.fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span()));
5051
let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else {
5152
return;
5253
};

src/tools/clippy/clippy_lints/src/functions/must_use.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
9595
}
9696
}
9797

98+
// FIXME: needs to be an EARLY LINT. all attribute lints should be
9899
#[allow(clippy::too_many_arguments)]
99100
fn check_needless_must_use(
100101
cx: &LateContext<'_>,
@@ -117,7 +118,7 @@ fn check_needless_must_use(
117118
fn_header_span,
118119
"this unit-returning function has a `#[must_use]` attribute",
119120
|diag| {
120-
diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable);
121+
diag.span_suggestion(attr.span(), "remove the attribute", "", Applicability::MachineApplicable);
121122
},
122123
);
123124
} else {
@@ -130,7 +131,7 @@ fn check_needless_must_use(
130131
"this unit-returning function has a `#[must_use]` attribute",
131132
|diag| {
132133
let mut attrs_without_must_use = attrs.to_vec();
133-
attrs_without_must_use.retain(|a| a.id != attr.id);
134+
attrs_without_must_use.retain(|a| a.id() != attr.id());
134135
let sugg_str = attrs_without_must_use
135136
.iter()
136137
.map(|a| {
@@ -143,7 +144,7 @@ fn check_needless_must_use(
143144
.join(", ");
144145

145146
diag.span_suggestion(
146-
attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()),
147+
attrs[0].span().with_hi(attrs[attrs.len() - 1].span().hi()),
147148
"change these attributes to",
148149
sugg_str,
149150
Applicability::MachineApplicable,

src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ fn suggestion<'tcx>(
183183

184184
fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span {
185185
if let Some(attr) = tcx.hir().attrs(field.hir_id).first() {
186-
field.span.with_lo(attr.span.lo())
186+
field.span.with_lo(attr.span().lo())
187187
} else {
188188
field.span
189189
}

src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
4242
span_lint_and_then(
4343
cx,
4444
INLINE_FN_WITHOUT_BODY,
45-
attr.span,
45+
attr.span(),
4646
format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
4747
|diag| {
48-
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
48+
diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable);
4949
},
5050
);
5151
}

0 commit comments

Comments
 (0)