Skip to content

Commit b207f23

Browse files
committed
Auto merge of #6725 - Y-Nak:refactor-types-lints, r=flip1995
Refactor types lints Ref #6724. As described in #6724, `types.rs` contains many groups inside it. In this PR, I reorganize the lints of the `types` group into their own modules. changelog: none
2 parents d0d5232 + db59c35 commit b207f23

File tree

9 files changed

+485
-357
lines changed

9 files changed

+485
-357
lines changed
+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use rustc_errors::Applicability;
2+
use rustc_hir::{
3+
self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath,
4+
SyntheticTyParamKind, TyKind,
5+
};
6+
use rustc_lint::LateContext;
7+
8+
use if_chain::if_chain;
9+
10+
use crate::utils::{match_path, paths, snippet, span_lint_and_sugg};
11+
12+
use super::BORROWED_BOX;
13+
14+
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, mut_ty: &MutTy<'_>) -> bool {
15+
match mut_ty.ty.kind {
16+
TyKind::Path(ref qpath) => {
17+
let hir_id = mut_ty.ty.hir_id;
18+
let def = cx.qpath_res(qpath, hir_id);
19+
if_chain! {
20+
if let Some(def_id) = def.opt_def_id();
21+
if Some(def_id) == cx.tcx.lang_items().owned_box();
22+
if let QPath::Resolved(None, ref path) = *qpath;
23+
if let [ref bx] = *path.segments;
24+
if let Some(ref params) = bx.args;
25+
if !params.parenthesized;
26+
if let Some(inner) = params.args.iter().find_map(|arg| match arg {
27+
GenericArg::Type(ty) => Some(ty),
28+
_ => None,
29+
});
30+
then {
31+
if is_any_trait(inner) {
32+
// Ignore `Box<Any>` types; see issue #1884 for details.
33+
return false;
34+
}
35+
36+
let ltopt = if lt.is_elided() {
37+
String::new()
38+
} else {
39+
format!("{} ", lt.name.ident().as_str())
40+
};
41+
42+
if mut_ty.mutbl == Mutability::Mut {
43+
// Ignore `&mut Box<T>` types; see issue #2907 for
44+
// details.
45+
return false;
46+
}
47+
48+
// When trait objects or opaque types have lifetime or auto-trait bounds,
49+
// we need to add parentheses to avoid a syntax error due to its ambiguity.
50+
// Originally reported as the issue #3128.
51+
let inner_snippet = snippet(cx, inner.span, "..");
52+
let suggestion = match &inner.kind {
53+
TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
54+
format!("&{}({})", ltopt, &inner_snippet)
55+
},
56+
TyKind::Path(qpath)
57+
if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
58+
.map_or(false, |bounds| bounds.len() > 1) =>
59+
{
60+
format!("&{}({})", ltopt, &inner_snippet)
61+
},
62+
_ => format!("&{}{}", ltopt, &inner_snippet),
63+
};
64+
span_lint_and_sugg(
65+
cx,
66+
BORROWED_BOX,
67+
hir_ty.span,
68+
"you seem to be trying to use `&Box<T>`. Consider using just `&T`",
69+
"try",
70+
suggestion,
71+
// To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
72+
// because the trait impls of it will break otherwise;
73+
// and there may be other cases that result in invalid code.
74+
// For example, type coercion doesn't work nicely.
75+
Applicability::Unspecified,
76+
);
77+
return true;
78+
}
79+
};
80+
false
81+
},
82+
_ => false,
83+
}
84+
}
85+
86+
// Returns true if given type is `Any` trait.
87+
fn is_any_trait(t: &hir::Ty<'_>) -> bool {
88+
if_chain! {
89+
if let TyKind::TraitObject(ref traits, _) = t.kind;
90+
if !traits.is_empty();
91+
// Only Send/Sync can be used as additional traits, so it is enough to
92+
// check only the first trait.
93+
if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
94+
then {
95+
return true;
96+
}
97+
}
98+
99+
false
100+
}
101+
102+
fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
103+
if_chain! {
104+
if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
105+
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
106+
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
107+
if synthetic == Some(SyntheticTyParamKind::ImplTrait);
108+
then {
109+
Some(generic_param.bounds)
110+
} else {
111+
None
112+
}
113+
}
114+
}

clippy_lints/src/types/box_vec.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use rustc_hir::{self as hir, def_id::DefId, QPath};
2+
use rustc_lint::LateContext;
3+
use rustc_span::symbol::sym;
4+
5+
use crate::utils::{is_ty_param_diagnostic_item, span_lint_and_help};
6+
7+
use super::BOX_VEC;
8+
9+
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
10+
if Some(def_id) == cx.tcx.lang_items().owned_box()
11+
&& is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some()
12+
{
13+
span_lint_and_help(
14+
cx,
15+
BOX_VEC,
16+
hir_ty.span,
17+
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
18+
None,
19+
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation",
20+
);
21+
true
22+
} else {
23+
false
24+
}
25+
}

clippy_lints/src/types/linked_list.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use rustc_hir::{self as hir, def_id::DefId};
2+
use rustc_lint::LateContext;
3+
4+
use crate::utils::{match_def_path, paths, span_lint_and_help};
5+
6+
use super::LINKEDLIST;
7+
8+
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, def_id: DefId) -> bool {
9+
if match_def_path(cx, def_id, &paths::LINKED_LIST) {
10+
span_lint_and_help(
11+
cx,
12+
LINKEDLIST,
13+
hir_ty.span,
14+
"you seem to be using a `LinkedList`! Perhaps you meant some other data structure?",
15+
None,
16+
"a `VecDeque` might work",
17+
);
18+
true
19+
} else {
20+
false
21+
}
22+
}

0 commit comments

Comments
 (0)