1
1
use clippy_utils:: consts:: { miri_to_const, Constant } ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_sugg;
3
3
use clippy_utils:: source:: snippet;
4
+ use rustc_ast:: Attribute ;
4
5
use rustc_errors:: Applicability ;
5
6
use rustc_hir:: def_id:: LocalDefId ;
6
- use rustc_hir:: { Item , ItemKind , TyKind , VariantData } ;
7
+ use rustc_hir:: { Item , ItemKind , VariantData } ;
7
8
use rustc_lint:: { LateContext , LateLintPass } ;
9
+ use rustc_middle:: dep_graph:: DepContext ;
10
+ use rustc_middle:: ty as ty_mod;
11
+ use rustc_middle:: ty:: ReprFlags ;
8
12
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
13
use rustc_span:: sym;
10
14
@@ -33,19 +37,16 @@ declare_clippy_lint! {
33
37
/// ```
34
38
pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C ,
35
39
nursery,
36
- "struct with a trailing zero-sized array but without `repr(C)`"
40
+ "struct with a trailing zero-sized array but without `repr(C)` or another `repr` attribute "
37
41
}
38
42
declare_lint_pass ! ( TrailingZeroSizedArrayWithoutReprC => [ TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C ] ) ;
39
43
40
- //
41
- // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
42
- // e.g. store.register_early_pass(||
43
- // Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC));
44
- // DONE!
44
+ // TESTNAME=trailing_zero_sized_array_without_repr_c cargo uitest
45
45
46
46
impl < ' tcx > LateLintPass < ' tcx > for TrailingZeroSizedArrayWithoutReprC {
47
47
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' tcx > ) {
48
- if is_struct_with_trailing_zero_sized_array ( cx, item) && !has_repr_c ( cx, item. def_id ) {
48
+ dbg ! ( item. ident) ;
49
+ if is_struct_with_trailing_zero_sized_array ( cx, item) && !has_repr_attr ( cx, item. def_id ) {
49
50
span_lint_and_sugg (
50
51
cx,
51
52
TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C ,
@@ -64,7 +65,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx
64
65
if let ItemKind :: Struct ( data, _generics) = & item. kind;
65
66
if let VariantData :: Struct ( field_defs, _) = data;
66
67
if let Some ( last_field) = field_defs. last( ) ;
67
- if let TyKind :: Array ( _, aconst) = last_field. ty. kind;
68
+ if let rustc_hir :: TyKind :: Array ( _, aconst) = last_field. ty. kind;
68
69
let aconst_def_id = cx. tcx. hir( ) . body_owner_def_id( aconst. body) . to_def_id( ) ;
69
70
let ty = cx. tcx. type_of( aconst_def_id) ;
70
71
let constant = cx
@@ -83,17 +84,50 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx
83
84
}
84
85
}
85
86
86
- fn has_repr_c ( cx : & LateContext < ' tcx > , def_id : LocalDefId ) -> bool {
87
+ fn has_repr_attr ( cx : & LateContext < ' tcx > , def_id : LocalDefId ) -> bool {
88
+ let attrs_get_attrs = get_attrs_get_attrs ( cx, def_id) ;
89
+ let attrs_hir_map = get_attrs_hir_map ( cx, def_id) ;
90
+ let b11 = dbg ! ( includes_repr_attr_using_sym( attrs_get_attrs) ) ;
91
+ let b12 = dbg ! ( includes_repr_attr_using_sym( attrs_hir_map) ) ;
92
+ let b21 = dbg ! ( includes_repr_attr_using_helper( cx, attrs_get_attrs) ) ;
93
+ let b22 = dbg ! ( includes_repr_attr_using_helper( cx, attrs_hir_map) ) ;
94
+ let b3 = dbg ! ( has_repr_attr_using_adt( cx, def_id) ) ;
95
+ let all_same = b11 && b12 && b21 && b22 && b3;
96
+ dbg ! ( all_same) ;
97
+
98
+ b11
99
+ }
100
+
101
+ fn get_attrs_get_attrs ( cx : & LateContext < ' tcx > , def_id : LocalDefId ) -> & ' tcx [ Attribute ] {
102
+ cx. tcx . get_attrs ( def_id. to_def_id ( ) )
103
+ }
104
+
105
+ fn get_attrs_hir_map ( cx : & LateContext < ' tcx > , def_id : LocalDefId ) -> & ' tcx [ Attribute ] {
87
106
let hir_map = cx. tcx . hir ( ) ;
88
107
let hir_id = hir_map. local_def_id_to_hir_id ( def_id) ;
89
- let attrs = hir_map. attrs ( hir_id) ;
108
+ hir_map. attrs ( hir_id)
109
+ }
90
110
91
- // NOTE: Can there ever be more than one `repr` attribute?
92
- // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed,
93
- // repr_simd, repr_transparent
94
- if let Some ( _attr) = attrs. iter ( ) . find ( |attr| attr. has_name ( sym:: repr) ) {
95
- true
111
+ // Don't like this because it's so dependent on the current list of `repr` flags and it would have to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or elsewhere for requiring that sort of exhaustiveness
112
+ fn has_repr_attr_using_adt ( cx : & LateContext < ' tcx > , def_id : LocalDefId ) -> bool {
113
+ let ty = cx. tcx . type_of ( def_id. to_def_id ( ) ) ;
114
+ if let ty_mod:: Adt ( adt, _) = ty. kind ( ) {
115
+ if adt. is_struct ( ) {
116
+ let repr = adt. repr ;
117
+ let repr_attr = ReprFlags :: IS_C | ReprFlags :: IS_TRANSPARENT | ReprFlags :: IS_SIMD | ReprFlags :: IS_LINEAR ;
118
+ repr. int . is_some ( ) || repr. align . is_some ( ) || repr. pack . is_some ( ) || repr. flags . intersects ( repr_attr)
119
+ } else {
120
+ false
121
+ }
96
122
} else {
97
123
false
98
124
}
99
125
}
126
+
127
+ fn includes_repr_attr_using_sym ( attrs : & ' tcx [ Attribute ] ) -> bool {
128
+ attrs. iter ( ) . any ( |attr| attr. has_name ( sym:: repr) )
129
+ }
130
+
131
+ fn includes_repr_attr_using_helper ( cx : & LateContext < ' tcx > , attrs : & ' tcx [ Attribute ] ) -> bool {
132
+ attrs. iter ( ) . any ( |attr| !rustc_attr:: find_repr_attrs ( cx. tcx . sess ( ) , attr) . is_empty ( ) )
133
+ }
0 commit comments