Skip to content

Commit 8e032a6

Browse files
committed
Last commit
1 parent edb006f commit 8e032a6

File tree

2 files changed

+361
-126
lines changed

2 files changed

+361
-126
lines changed

clippy_lints/src/functions/hidden_static_lifetime.rs

+149-126
Original file line numberDiff line numberDiff line change
@@ -7,124 +7,149 @@ use rustc_hir::{
77
};
88
use rustc_lint::LateContext;
99
use rustc_middle::lint::in_external_macro;
10-
use rustc_span::Span;
10+
use rustc_span::{symbol::Ident, Span};
1111

1212
use super::HIDDEN_STATIC_LIFETIME;
1313

14-
// As a summary:
15-
//
16-
// A lifetime can only be changed if:
17-
// * Used in immutable references.
18-
// * Not behind a mutable reference.
19-
// * Not used in function types
20-
//
21-
// NOTE: Struct's fields follow the same rules as types
22-
23-
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, span: Span) {
24-
if !in_external_macro(cx.sess(), span) &&
25-
let FnKind::ItemFn(_, generics, _) = kind {
26-
27-
let mut v = FuncVisitor {
28-
ret_ty: &decl.output,
29-
inputs: decl.inputs,
30-
predicates: &generics.predicates,
31-
lifetime_is_used: false
32-
};
33-
34-
for param in generics.params {
35-
if let GenericParamKind::Lifetime { kind } = param.kind && kind != LifetimeParamKind::Elided {
36-
v.visit_generic_param(param);
37-
if !v.lifetime_is_used {
38-
span_lint(cx, HIDDEN_STATIC_LIFETIME, param.span, "hi");
39-
};
40-
}
41-
};
42-
}
14+
struct V<'a> {
15+
// (Lifetime, Bounded typ)
16+
lifetimes: Vec<&'a GenericParam<'a>>,
4317
}
4418

45-
struct FuncVisitor<'a> {
46-
ret_ty: &'a FnRetTy<'a>,
47-
inputs: &'a [Ty<'a>],
48-
predicates: &'a [WherePredicate<'a>],
49-
lifetime_is_used: bool,
50-
}
19+
impl<'a> Visitor<'_> for V<'a> {
20+
/// Remove all mutable lifetimes that aren't for T: 'static
21+
fn visit_where_predicate(&mut self, predicate: &WherePredicate<'_>) {
22+
if let WherePredicate::BoundPredicate(pred) = predicate {
23+
for bound in pred.bounds {
24+
// Check (for each lifetime) that the type they're associated with is 'static.
25+
continue;
26+
}
27+
}
28+
}
5129

52-
impl<'v> Visitor<'_> for FuncVisitor<'v> {
53-
fn visit_generic_param(&mut self, param: &GenericParam<'_>) {
54-
// Check inputs
55-
for input in self.inputs {
56-
if ref_uses_lifetime(input, param) || check_path(input, param) {
57-
dbg!("@@@@@@@@@@@@@@@@@@@@@@@@");
58-
self.lifetime_is_used = true;
59-
return;
60-
};
61-
}
30+
fn visit_ty(&mut self, ty: &Ty<'_>) {
31+
let mut outer_continue: bool;
32+
let mut outer_break = false;
33+
let mut i = 0;
34+
while i < self.lifetimes.len() {
35+
outer_continue = false;
36+
let lifetime = self.lifetimes[i];
37+
38+
// Check references
39+
40+
let mut final_ty = ty;
41+
let mut behind_mut_ref = false;
42+
while let TyKind::Ref(lt, mut_ty) = &final_ty.kind {
43+
if mut_ty.mutbl.is_mut() {
44+
behind_mut_ref = true;
45+
};
6246

63-
// Check return
64-
if let FnRetTy::Return(ret_ty) = self.ret_ty {
65-
if ref_uses_lifetime(ret_ty, param) || check_path(ret_ty, param) {
66-
dbg!("============================");
67-
self.lifetime_is_used = true;
68-
return;
69-
};
70-
};
47+
if lt.ident.name == lifetime.name.ident().name || behind_mut_ref {
48+
if self.lifetimes.is_empty() {
49+
outer_continue = true;
50+
continue;
51+
}
52+
53+
self.lifetimes.remove(i);
54+
outer_continue = true;
55+
56+
}
57+
final_ty = mut_ty.ty;
58+
}
7159

72-
// Check predicates
60+
if outer_continue {
61+
continue;
62+
} else if outer_break {
63+
break;
64+
}
7365

74-
for predicate in self.predicates {
75-
for bound in predicate.bounds() {
76-
if let GenericBound::Outlives(lifetime) = bound &&
77-
lifetime.ident.name == param.name.ident().name {
78-
self.lifetime_is_used = true;
79-
return;
66+
// Now final_ty is equal to ty.peel_refs()
67+
// Check Paths:
68+
69+
if let TyKind::Path(QPath::Resolved(_, path)) = final_ty.kind {
70+
for segment in path.segments {
71+
for argument in segment.args().args {
72+
if let GenericArg::Lifetime(lt) = argument && lt.ident.name == lifetime.name.ident().name {
73+
self.lifetimes.remove(i);
74+
outer_continue = true;
75+
continue;
76+
};
77+
}
78+
if outer_continue {
79+
break;
80+
}
8081
}
82+
};
83+
84+
if outer_continue {
85+
continue;
8186
}
87+
i += 1;
8288
}
8389
}
84-
}
8590

86-
fn ref_uses_lifetime(mut ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool {
87-
while let TyKind::Ref(lt_ref, mut_ty) = &ty.kind {
88-
if lt_ref.ident.name == lifetime.name.ident().name && mut_ty.mutbl.is_not() {
89-
return true;
90-
} else {
91-
ty = mut_ty.ty;
91+
fn visit_fn_ret_ty<'v>(&mut self, ret_ty: &'v FnRetTy<'v>) {
92+
if let FnRetTy::Return(ty) = ret_ty {
93+
let mut i = 0;
94+
while i < self.lifetimes.len() {
95+
dbg!(self.lifetimes[i].name.ident().as_str());
96+
if ty_uses_lifetime(ty, &self.lifetimes[i], &self) {
97+
self.lifetimes.remove(i);
98+
}
99+
i += 1;
100+
}
92101
}
93102
}
94-
false
95103
}
96104

97-
fn check_path(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool {
98-
if let TyKind::Path(QPath::Resolved(_, path)) = ty.peel_refs().kind {
99-
for segment in path.segments {
100-
for arg in segment.args().args {
101-
if let GenericArg::Lifetime(lt_arg) = arg {
102-
if lt_arg.ident.name == lifetime.name.ident().name {
103-
return true;
104-
};
105-
} else if let &GenericArg::Type(ty) = arg {
106-
dbg!("!!!!!!!!!!!!!!!!!!!!!!!!!");
107-
return check_all_types(ty, lifetime);
108-
};
109-
}
110-
}
111-
};
112-
false
105+
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, span: Span) {
106+
if !in_external_macro(cx.sess(), span) &&
107+
let FnKind::ItemFn(_, generics, _) = kind {
108+
let mut visitor = V {
109+
lifetimes: Vec::new()
110+
};
111+
112+
// Fill visitor.lifetimes with function's lifetimes
113+
114+
for generic in generics.params {
115+
if let GenericParamKind::Lifetime { .. } = generic.kind {
116+
visitor.lifetimes.push(generic);
117+
};
118+
};
119+
120+
for input in decl.inputs {
121+
visitor.visit_ty(input);
122+
}
123+
124+
for predicate in generics.predicates {
125+
visitor.visit_where_predicate(predicate);
126+
}
127+
visitor.visit_fn_ret_ty(&decl.output);
128+
129+
for generic in visitor.lifetimes {
130+
span_lint_and_help(cx,
131+
HIDDEN_STATIC_LIFETIME,
132+
generic.span,
133+
"this lifetime can be changed to `'static`",
134+
None,
135+
&format!("try removing the lifetime parameter `{}` and changing references to `'static`", generic.name.ident().as_str()));
136+
}
137+
};
113138
}
114139

115-
fn check_all_types(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool {
116-
fn ty_uses_lifetime(ty: &Ty<'_>, generic: &GenericParam<'_>) -> bool {
117-
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
140+
fn ty_uses_lifetime(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool {
141+
fn check_ty(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool {
142+
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
118143
for segment in path.segments {
119144
if let Some(GenericArgs { args, .. }) = segment.args {
120145
for arg in args.iter() {
121146
if let GenericArg::Lifetime(lifetime) = arg {
122-
if lifetime.ident.name == generic.name.ident().name {
147+
if lifetime.ident.name == generic.name.ident().name {
123148
// generic is used
124149
return true;
125150
}
126151
} else if let GenericArg::Type(ty) = arg {
127-
return classify_ty(ty, generic);
152+
return classify_ty(ty, generic, v);
128153
}
129154
}
130155
}
@@ -134,37 +159,34 @@ fn check_all_types(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool {
134159
}
135160

136161
#[inline]
137-
fn barefn_uses_lifetime(barefn: &BareFnTy<'_>, generic: &GenericParam<'_>) -> bool {
138-
// Check inputs
139-
for input in barefn.decl.inputs {
140-
if ref_uses_lifetime(input, generic) || check_path(input, generic) {
141-
return false;
142-
};
143-
}
144-
145-
// Check return
146-
if let FnRetTy::Return(ret_ty) = barefn.decl.output {
147-
if check_path(ret_ty, generic) {
148-
return false;
149-
};
150-
};
151-
true
152-
}
162+
fn barefn_uses_lifetime(barefn: &BareFnTy<'_>, generic: &GenericParam, v: &V<'_>) -> bool {
163+
// let mut visitor = V {
164+
// lifetimes: v.lifetimes.clone(),
165+
// };
166+
167+
// for input in barefn.decl.inputs {
168+
// visitor.visit_ty(input);
169+
// }
170+
171+
// visitor.visit_fn_ret_ty(&barefn.decl.output);
172+
// !visitor.lifetimes.contains(&generic)
173+
true
174+
}
153175

154176
#[inline]
155-
fn tuple_uses_lifetime(tuple: &[Ty<'_>], generic: &GenericParam<'_>) -> bool {
156-
tuple.iter().any(|ty| classify_ty(ty, generic))
177+
fn tuple_uses_lifetime(tuple: &[Ty<'_>], generic: &GenericParam, v: &V<'_>) -> bool {
178+
tuple.iter().any(|ty| classify_ty(ty, generic, v))
157179
}
158180

159-
fn opaquedef_uses_lifetime(args: &[GenericArg<'_>], generic: &GenericParam<'_>) -> bool {
181+
fn opaquedef_uses_lifetime(args: &[GenericArg<'_>], generic: &GenericParam, v: &V<'_>) -> bool {
160182
for arg in args.iter() {
161183
if let GenericArg::Lifetime(lifetime) = arg {
162184
if lifetime.ident.name == generic.name.ident().name {
163185
// generic is used
164186
return true;
165187
}
166188
} else if let GenericArg::Type(ty) = arg {
167-
return classify_ty(ty, generic);
189+
return classify_ty(ty, generic, v);
168190
}
169191
}
170192
false
@@ -173,40 +195,41 @@ fn check_all_types(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool {
173195
#[inline]
174196
fn traitobject_uses_lifetime(lifetime: &Lifetime, traits: &[PolyTraitRef<'_>], generic: &GenericParam<'_>) -> bool {
175197
if lifetime.ident.name == generic.name.ident().name {
176-
return true;
198+
return false;
177199
}
178200
for PolyTraitRef {
179201
bound_generic_params, ..
180202
} in traits
181203
{
182-
if bound_generic_params.iter().any(|param| param.def_id == generic.def_id) {
204+
if bound_generic_params
205+
.iter()
206+
.any(|param| param.name.ident().name == generic.name.ident().name)
207+
{
183208
return true;
184209
};
185210
}
186211
false
187212
}
188213

189214
#[inline]
190-
fn classify_ty(ty: &Ty<'_>, generic: &GenericParam<'_>) -> bool {
215+
fn classify_ty(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool {
191216
match &ty.kind {
192-
TyKind::Slice(ty) | TyKind::Array(ty, _) => ty_uses_lifetime(ty, generic),
193-
TyKind::Ptr(mut_ty) => ty_uses_lifetime(mut_ty.ty, generic),
194-
TyKind::BareFn(barefnty) => barefn_uses_lifetime(barefnty, generic),
195-
TyKind::Tup(tuple) => tuple_uses_lifetime(tuple, generic),
196-
TyKind::Path(_) => ty_uses_lifetime(ty, generic),
197-
TyKind::OpaqueDef(_, genericargs, _) => opaquedef_uses_lifetime(genericargs, generic),
217+
TyKind::Slice(ty) | TyKind::Array(ty, _) => check_ty(ty, generic, v),
218+
TyKind::Ptr(mut_ty) => check_ty(mut_ty.ty, generic, v),
219+
TyKind::BareFn(barefnty) => {
220+
barefn_uses_lifetime(barefnty, generic, v)},
221+
TyKind::Tup(tuple) => tuple_uses_lifetime(tuple, generic, v),
222+
TyKind::Path(_) => check_ty(ty, generic, v),
223+
TyKind::OpaqueDef(_, genericargs, _) => opaquedef_uses_lifetime(genericargs, generic, v),
198224
TyKind::TraitObject(poly_trait_ref, lifetime, _) =>
199225
traitobject_uses_lifetime(lifetime, poly_trait_ref, generic),
200226
TyKind::Typeof(_) // This is unused for now, this needs revising when Typeof is used.
201227
| TyKind::Err
202-
| TyKind::Never => false,
203-
TyKind::Ref(_, MutTy { ty, ..}) => ref_uses_lifetime(ty, generic),
204-
TyKind::Infer => true,
228+
| TyKind::Never
229+
| TyKind::Ref(_, _)
230+
| TyKind::Infer => true,
205231
}
206232
}
207233

208-
// Separate refs from ty.
209-
210-
// Now final_ty is equivalent to ty.peel_refs
211-
return classify_ty(ty.peel_refs(), lifetime);
234+
return classify_ty(ty.peel_refs(), &generic, v);
212235
}

0 commit comments

Comments
 (0)