diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 10088ea55a9..0c9066fda82 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -2,12 +2,10 @@ use clippy_utils::{ diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, source::{indent_of, snippet}, }; -use rustc_ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::{self as ty_mod, Const, ReprFlags}; +use rustc_middle::ty::{Const, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -43,18 +41,28 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARR impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item) { - eprintln!("consider yourself linted 😎"); - // span_lint_and_help( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - // item.span, - // "trailing zero-sized array in a struct which is not marked with a `repr` - // attribute", - // None, - // "consider annotating the struct definition with `#[repr(C)]` or another - // `repr` attribute", - // ); + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { + let help_msg = format!( + "consider annotating {} with `#[repr(C)]` or another `repr` attribute", + cx.tcx + .type_of(item.def_id) + .ty_adt_def() + .map(|adt_def| cx.tcx.def_path_str(adt_def.did)) + .unwrap_or_else( + // I don't think this will ever be the case, since we made it through + // `is_struct_with_trailing_zero_sized_array`, but I don't feel comfortable putting an `unwrap` + || "the struct definition".to_string() + ) + ); + + span_lint_and_help( + cx, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + item.span, + "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + None, + &help_msg, + ); } } } @@ -83,52 +91,9 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_attr(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { +fn has_repr_attr(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; + // on all testcases.) Happy to use another; // they're in the commit history if you want to look (or I can go find them). - - let attrs1 = cx.tcx.hir().attrs(item.hir_id()); - let attrs2 = cx.tcx.get_attrs(item.def_id.to_def_id()); - - let res11 = { - let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? - attrs1 - .iter() - .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) - }; - let res12 = { attrs1.iter().any(|attr| attr.has_name(sym::repr)) }; - - let res21 = { - let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? - attrs2 - .iter() - .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) - }; - let res22 = { attrs2.iter().any(|attr| attr.has_name(sym::repr)) }; - - let res_adt = { - let ty = cx.tcx.type_of(item.def_id.to_def_id()); - if let ty_mod::Adt(adt, _) = ty.kind() { - if adt.is_struct() { - let repr = adt.repr; - let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR; - repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr) - } else { - false - } - } else { - false - } - }; - - let all_same = (res11 && res12 && res21 && res22 && res_adt) || (!res11 && !res12 && !res21 && !res22 && !res_adt); - - - dbg!(( - (res11, res12, res21, res22, res_adt), - all_same, - )); - - res12 + cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr)) }