Skip to content

Commit d8bacf0

Browse files
committed
All five has_repr_attr agree + are correct
1 parent 3a41f22 commit d8bacf0

File tree

1 file changed

+65
-50
lines changed

1 file changed

+65
-50
lines changed
Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
use clippy_utils::{diagnostics::{span_lint_and_help, span_lint_and_then, span_lint_and_sugg}, source::{indent_of, snippet}};
1+
use clippy_utils::{
2+
diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then},
3+
source::{indent_of, snippet},
4+
};
25
use rustc_ast::Attribute;
36
use rustc_errors::Applicability;
4-
use rustc_hir::{Item, ItemKind};
7+
use rustc_hir::{HirId, Item, ItemKind};
58
use rustc_lint::{LateContext, LateLintPass};
69
use rustc_middle::dep_graph::DepContext;
7-
use rustc_middle::ty::Const;
10+
use rustc_middle::ty::{self as ty_mod, Const, ReprFlags};
811
use rustc_session::{declare_lint_pass, declare_tool_lint};
12+
use rustc_span::sym;
913

1014
declare_clippy_lint! {
1115
/// ### What it does
@@ -38,48 +42,19 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARR
3842

3943
impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr {
4044
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
41-
if is_struct_with_trailing_zero_sized_array(cx, item) {
42-
// NOTE: This is to include attributes on the definition when we print the lint. If the convention
43-
// is to not do that with struct definitions (I'm not sure), then this isn't necessary. (note: if
44-
// you don't get rid of this, change `has_repr_attr` to `includes_repr_attr`).
45-
let attrs = cx.tcx.get_attrs(item.def_id.to_def_id());
46-
let first_attr = attrs.iter().min_by_key(|attr| attr.span.lo());
47-
let lint_span = if let Some(first_attr) = first_attr {
48-
first_attr.span.to(item.span)
49-
} else {
50-
item.span
51-
};
52-
53-
if !has_repr_attr(cx, attrs) {
54-
let suggestion_span = item.span.shrink_to_lo();
55-
let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
56-
57-
span_lint_and_sugg(cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", "consider adding `#[repr(C)]` or another `repr` attribute", format!("#[repr(C)]\n{}", snippet(cx, item.span.shrink_to_lo().to(item.ident.span), "..")), Applicability::MaybeIncorrect);
58-
59-
// span_lint_and_then(
60-
// cx,
61-
// TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
62-
// item.span,
63-
// "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
64-
// |diag| {
65-
// let sugg = format!("#[repr(C)]\n{}", indent);
66-
// let sugg2 = format!("#[repr(C)]\n{}", item.ident.span);
67-
// diag.span_suggestion(item.span,
68-
// "consider adding `#[repr(C)]` or another `repr` attribute",
69-
// sugg2,
70-
// Applicability::MaybeIncorrect);
71-
// }
72-
// );
73-
74-
// span_lint_and_help(
75-
// cx,
76-
// TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
77-
// lint_span,
78-
// "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
79-
// None,
80-
// "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute",
81-
// );
82-
}
45+
dbg!(item.ident);
46+
if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item) {
47+
eprintln!("consider yourself linted 😎");
48+
// span_lint_and_help(
49+
// cx,
50+
// TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
51+
// item.span,
52+
// "trailing zero-sized array in a struct which is not marked with a `repr`
53+
// attribute",
54+
// None,
55+
// "consider annotating the struct definition with `#[repr(C)]` or another
56+
// `repr` attribute",
57+
// );
8358
}
8459
}
8560
}
@@ -108,12 +83,52 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx
10883
}
10984
}
11085

111-
fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool {
86+
fn has_repr_attr(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
11287
// NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed
11388
// on all testcases (when i wrote this comment. I added a few since then).) Happy to use another;
11489
// they're in the commit history if you want to look (or I can go find them).
115-
let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
116-
attrs
117-
.iter()
118-
.any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
90+
91+
let attrs1 = cx.tcx.hir().attrs(item.hir_id());
92+
let attrs2 = cx.tcx.get_attrs(item.def_id.to_def_id());
93+
94+
let res11 = {
95+
let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
96+
attrs1
97+
.iter()
98+
.any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
99+
};
100+
let res12 = { attrs1.iter().any(|attr| attr.has_name(sym::repr)) };
101+
102+
let res21 = {
103+
let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
104+
attrs2
105+
.iter()
106+
.any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
107+
};
108+
let res22 = { attrs2.iter().any(|attr| attr.has_name(sym::repr)) };
109+
110+
let res_adt = {
111+
let ty = cx.tcx.type_of(item.def_id.to_def_id());
112+
if let ty_mod::Adt(adt, _) = ty.kind() {
113+
if adt.is_struct() {
114+
let repr = adt.repr;
115+
let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR;
116+
repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr)
117+
} else {
118+
false
119+
}
120+
} else {
121+
false
122+
}
123+
};
124+
125+
let all_same = (res11 && res12 && res21 && res22 && res_adt) || (!res11 && !res12 && !res21 && !res22 && !res_adt);
126+
127+
128+
dbg!((
129+
(res11, res12, res21, res22, res_adt),
130+
all_same,
131+
));
132+
133+
res12
119134
}

0 commit comments

Comments
 (0)