Skip to content

Commit fd4f98d

Browse files
committed
Add struct field's mutability checking + Testing
1 parent 53aab19 commit fd4f98d

File tree

3 files changed

+106
-23
lines changed

3 files changed

+106
-23
lines changed

clippy_lints/src/functions/hidden_static_lifetime.rs

+56-17
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use crate::rustc_lint::LintContext;
22
use clippy_utils::diagnostics::span_lint_and_help;
33
use rustc_hir::{
4-
intravisit::FnKind, FnDecl, FnRetTy, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics,
5-
LifetimeParamKind, ParamName, QPath, Ty, TyKind, TypeBindingKind, WherePredicate,
4+
def::{DefKind, Res},
5+
intravisit::FnKind,
6+
FnDecl, FnRetTy, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ItemKind, LifetimeParamKind,
7+
Node, ParamName, QPath, Ty, TyKind, TypeBindingKind, WherePredicate,
68
};
79
use rustc_lint::LateContext;
8-
use rustc_middle::lint::in_external_macro;
10+
use rustc_middle::{hir::map::Map, lint::in_external_macro};
911
use rustc_span::Span;
1012

1113
use super::HIDDEN_STATIC_LIFETIME;
1214

1315
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, span: Span) {
14-
if !in_external_macro(cx.sess(), span) && let FnKind::ItemFn(_, generics, _) = kind {
15-
let mut lifetime_is_used;
16+
if !in_external_macro(cx.sess(), span) && let FnKind::ItemFn(_, generics, _) =
17+
kind { let mut lifetime_is_used;
1618
for generic in generics.params.iter() {
1719
if let GenericParamKind::Lifetime { kind } = generic.kind &&
1820
kind != LifetimeParamKind::Elided {
@@ -65,8 +67,8 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'t
6567
bound.span(),
6668
"this lifetime can be changed to `'static`",
6769
None,
68-
&format!("try removing the lifetime parameter `{}` and changing references to `'static`", generic.name.ident().as_str()),
69-
);
70+
&format!("try removing the lifetime parameter `{}` and changing references to `'static`",
71+
generic.name.ident().as_str()), );
7072
};
7173
};
7274
};
@@ -81,25 +83,27 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'t
8183
region_predicate.span,
8284
"this lifetime can be changed to `'static`",
8385
None,
84-
&format!("try removing the lifetime parameter `{}` and changing references to `'static`", generic.name.ident().as_str()),
85-
);
86+
&format!("try removing the lifetime parameter `{}` and changing references to `'static`",
87+
generic.name.ident().as_str()), );
8688
};
8789
};
8890
};
8991
};
9092

9193
// Check again.
92-
if !lifetime_is_used {
94+
if !lifetime_is_used &&
9395
// Check validness
94-
if check_validness(ret_ty, generic, generics) {
96+
check_validness(ret_ty, generic, generics)
97+
&& check_mut_fields(cx.tcx.hir(), &ret_ty.peel_refs().kind) {
9598
span_lint_and_help(cx,
96-
HIDDEN_STATIC_LIFETIME,
97-
generic.span,
98-
"this lifetime can be changed to `'static`",
99-
None,
100-
&format!("try removing the lifetime parameter `{}` and changing references to `'static`", generic.name.ident().as_str()),
99+
HIDDEN_STATIC_LIFETIME,
100+
generic.span,
101+
"this lifetime can be changed to `'static`",
102+
None,
103+
&format!(
104+
"try removing the lifetime parameter `{}` and changing references to `'static`",
105+
generic.name.ident().as_str()),
101106
);
102-
};
103107
};
104108
};
105109
};
@@ -166,3 +170,38 @@ fn check_validness(ret_ty: &Ty<'_>, generic: &GenericParam<'_>, generics: &Gener
166170
};
167171
true
168172
}
173+
174+
// true = no mut fields
175+
fn check_mut_fields(map: Map<'_>, tykind: &TyKind<'_>) -> bool {
176+
if_chain! {
177+
if let TyKind::Path(qpath) = tykind;
178+
if let QPath::Resolved(_, path) = qpath;
179+
if let Res::Def(defkind, def_id) = path.res;
180+
if let DefKind::Struct = defkind;
181+
then {
182+
if let Some(node) = map.get_if_local(def_id) {
183+
if let Node::Item(item) = node {
184+
if let ItemKind::Struct(variant_data, _) = &item.kind {
185+
for field in variant_data.fields() {
186+
if let TyKind::Ref(_, mut_ty) = &field.ty.kind {
187+
if mut_ty.mutbl.is_mut() {
188+
return false;
189+
};
190+
return true;
191+
} else if let TyKind::Ptr(mut_ty) = &field.ty.kind {
192+
if mut_ty.mutbl.is_mut() {
193+
return false;
194+
};
195+
return true;
196+
}
197+
}
198+
}
199+
};
200+
return true;
201+
};
202+
// Don't lint if struct isn't local.
203+
return false
204+
}
205+
};
206+
true
207+
}

tests/ui/hidden_static_lifetime.rs

+20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ mod module {
1212
}
1313
}
1414

15+
struct SMut<'a>(&'a mut i32);
16+
struct STuple<'a>(&'a i32);
17+
1518
// ============= Should warn =============
1619

1720
fn a<'a>() -> &'a str {
@@ -34,6 +37,15 @@ fn n<'m1, 'm2, T>() -> &'m1 fn(&'m2 T) {
3437
unsafe { std::ptr::null::<&'m1 fn(&'m2 T)>().read() }
3538
}
3639

40+
// Only 's1
41+
fn s<'s1, 's2>() -> &'s1 STuple<'s2> {
42+
unsafe { std::ptr::null::<&STuple<'s2>>().read() }
43+
}
44+
45+
fn q<'q>() -> STuple<'q> {
46+
STuple(&1)
47+
}
48+
3749
// ============= Should not warn =============
3850
fn b<'b>(_: &'b str) -> &'b str {
3951
""
@@ -78,4 +90,12 @@ where
7890
unsafe { std::ptr::null::<&mut T>().read() }
7991
}
8092

93+
fn p<'p>() -> SMut<'p> {
94+
unsafe { std::ptr::null::<SMut<'p>>().read() }
95+
}
96+
97+
fn r<'r1, 'r2>() -> &'r1 SMut<'r2> {
98+
unsafe { std::ptr::null::<&SMut<'r2>>().read() }
99+
}
100+
81101
fn main() {}
+30-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: this lifetime can be changed to `'static`
2-
--> $DIR/hidden_static_lifetime.rs:17:6
2+
--> $DIR/hidden_static_lifetime.rs:20:6
33
|
44
LL | fn a<'a>() -> &'a str {
55
| ^^
@@ -8,36 +8,60 @@ LL | fn a<'a>() -> &'a str {
88
= note: `-D clippy::hidden-static-lifetime` implied by `-D warnings`
99

1010
error: this lifetime can be changed to `'static`
11-
--> $DIR/hidden_static_lifetime.rs:20:6
11+
--> $DIR/hidden_static_lifetime.rs:23:6
1212
|
1313
LL | fn h<'h>() -> S<'h> {
1414
| ^^
1515
|
1616
= help: try removing the lifetime parameter `'h` and changing references to `'static`
1717

1818
error: this lifetime can be changed to `'static`
19-
--> $DIR/hidden_static_lifetime.rs:25:6
19+
--> $DIR/hidden_static_lifetime.rs:28:6
2020
|
2121
LL | fn o<'o, T>() -> &'o mut T
2222
| ^^
2323
|
2424
= help: try removing the lifetime parameter `'o` and changing references to `'static`
2525

2626
error: this lifetime can be changed to `'static`
27-
--> $DIR/hidden_static_lifetime.rs:33:6
27+
--> $DIR/hidden_static_lifetime.rs:36:6
2828
|
2929
LL | fn n<'m1, 'm2, T>() -> &'m1 fn(&'m2 T) {
3030
| ^^^
3131
|
3232
= help: try removing the lifetime parameter `'m1` and changing references to `'static`
3333

3434
error: this lifetime can be changed to `'static`
35-
--> $DIR/hidden_static_lifetime.rs:74:6
35+
--> $DIR/hidden_static_lifetime.rs:41:6
36+
|
37+
LL | fn s<'s1, 's2>() -> &'s1 STuple<'s2> {
38+
| ^^^
39+
|
40+
= help: try removing the lifetime parameter `'s1` and changing references to `'static`
41+
42+
error: this lifetime can be changed to `'static`
43+
--> $DIR/hidden_static_lifetime.rs:41:11
44+
|
45+
LL | fn s<'s1, 's2>() -> &'s1 STuple<'s2> {
46+
| ^^^
47+
|
48+
= help: try removing the lifetime parameter `'s2` and changing references to `'static`
49+
50+
error: this lifetime can be changed to `'static`
51+
--> $DIR/hidden_static_lifetime.rs:45:6
52+
|
53+
LL | fn q<'q>() -> STuple<'q> {
54+
| ^^
55+
|
56+
= help: try removing the lifetime parameter `'q` and changing references to `'static`
57+
58+
error: this lifetime can be changed to `'static`
59+
--> $DIR/hidden_static_lifetime.rs:86:6
3660
|
3761
LL | fn l<'l, T>() -> &'l mut T
3862
| ^^
3963
|
4064
= help: try removing the lifetime parameter `'l` and changing references to `'static`
4165

42-
error: aborting due to 5 previous errors
66+
error: aborting due to 8 previous errors
4367

0 commit comments

Comments
 (0)