Auto merge of #6938 - Y-Nak:refactor-types, r=flip1995

Refactor types

r? `@flip1995`
This is the last PR to close #6724 🎉
Also, this fixes #6936.

changelog: `vec_box`: Fix FN in `const` or `static`
changelog: `linkedlist`: Fix FN in `const` or `static`
changelog: `option_option`: Fix FN in `const` or `static`
This commit is contained in:
bors 2021-03-31 14:35:48 +00:00
commit 2e33bf6347
15 changed files with 1132 additions and 1055 deletions

View File

@ -0,0 +1,173 @@
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::consts::{constant, Constant};
use clippy_utils::comparisons::{normalize_comparison, Rel};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_isize_or_usize;
use clippy_utils::{clip, int_bits, unsext};
declare_clippy_lint! {
/// **What it does:** Checks for comparisons where one side of the relation is
/// either the minimum or maximum value for its type and warns if it involves a
/// case that is always true or always false. Only integer and boolean types are
/// checked.
///
/// **Why is this bad?** An expression like `min <= x` may misleadingly imply
/// that it is possible for `x` to be less than the minimum. Expressions like
/// `max < x` are probably mistakes.
///
/// **Known problems:** For `usize` the size of the current compile target will
/// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
/// a comparison to detect target pointer width will trigger this lint. One can
/// use `mem::sizeof` and compare its value or conditional compilation
/// attributes
/// like `#[cfg(target_pointer_width = "64")] ..` instead.
///
/// **Example:**
///
/// ```rust
/// let vec: Vec<isize> = Vec::new();
/// if vec.len() <= 0 {}
/// if 100 > i32::MAX {}
/// ```
pub ABSURD_EXTREME_COMPARISONS,
correctness,
"a comparison with a maximum or minimum value that is always true or false"
}
declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
if !expr.span.from_expansion() {
let msg = "this comparison involving the minimum or maximum element for this \
type contains a case that is always true or always false";
let conclusion = match result {
AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(),
AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(),
AbsurdComparisonResult::InequalityImpossible => format!(
"the case where the two sides are not equal never occurs, consider using `{} == {}` \
instead",
snippet(cx, lhs.span, "lhs"),
snippet(cx, rhs.span, "rhs")
),
};
let help = format!(
"because `{}` is the {} value for this type, {}",
snippet(cx, culprit.expr.span, "x"),
match culprit.which {
ExtremeType::Minimum => "minimum",
ExtremeType::Maximum => "maximum",
},
conclusion
);
span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
}
}
}
}
}
enum ExtremeType {
Minimum,
Maximum,
}
struct ExtremeExpr<'a> {
which: ExtremeType,
expr: &'a Expr<'a>,
}
enum AbsurdComparisonResult {
AlwaysFalse,
AlwaysTrue,
InequalityImpossible,
}
fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
let precast_ty = cx.typeck_results().expr_ty(cast_exp);
let cast_ty = cx.typeck_results().expr_ty(expr);
return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
}
false
}
fn detect_absurd_comparison<'tcx>(
cx: &LateContext<'tcx>,
op: BinOpKind,
lhs: &'tcx Expr<'_>,
rhs: &'tcx Expr<'_>,
) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
use AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
use ExtremeType::{Maximum, Minimum};
// absurd comparison only makes sense on primitive types
// primitive types don't implement comparison operators with each other
if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
return None;
}
// comparisons between fix sized types and target sized types are considered unanalyzable
if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
return None;
}
let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
let lx = detect_extreme_expr(cx, normalized_lhs);
let rx = detect_extreme_expr(cx, normalized_rhs);
Some(match rel {
Rel::Lt => {
match (lx, rx) {
(Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
(_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
_ => return None,
}
},
Rel::Le => {
match (lx, rx) {
(Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
(Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
(_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
(_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
_ => return None,
}
},
Rel::Ne | Rel::Eq => return None,
})
}
fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
let ty = cx.typeck_results().expr_ty(expr);
let cv = constant(cx, cx.typeck_results(), expr)?.0;
let which = match (ty.kind(), cv) {
(&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
(&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
ExtremeType::Minimum
},
(&ty::Bool, Constant::Bool(true)) => ExtremeType::Maximum,
(&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
ExtremeType::Maximum
},
(&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => ExtremeType::Maximum,
_ => return None,
};
Some(ExtremeExpr { which, expr })
}

View File

@ -0,0 +1,377 @@
#![allow(rustc::default_hash_types)]
use std::borrow::Cow;
use std::collections::BTreeMap;
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, NestedVisitorMap, Visitor};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Ty, TyS, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
use rustc_typeck::hir_ty_to_ty;
use if_chain::if_chain;
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::paths;
use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{differing_macro_contexts, match_path};
declare_clippy_lint! {
/// **What it does:** Checks for public `impl` or `fn` missing generalization
/// over different hashers and implicitly defaulting to the default hashing
/// algorithm (`SipHash`).
///
/// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
/// used with them.
///
/// **Known problems:** Suggestions for replacing constructors can contain
/// false-positives. Also applying suggestions can require modification of other
/// pieces of code, possibly including external crates.
///
/// **Example:**
/// ```rust
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};
/// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
///
/// pub fn foo(map: &mut HashMap<i32, i32>) { }
/// ```
/// could be rewritten as
/// ```rust
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};
/// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
///
/// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
/// ```
pub IMPLICIT_HASHER,
pedantic,
"missing generalization over different hashers"
}
declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
use rustc_span::BytePos;
fn suggestion<'tcx>(
cx: &LateContext<'tcx>,
diag: &mut DiagnosticBuilder<'_>,
generics_span: Span,
generics_suggestion_span: Span,
target: &ImplicitHasherType<'_>,
vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
) {
let generics_snip = snippet(cx, generics_span, "");
// trim `<` `>`
let generics_snip = if generics_snip.is_empty() {
""
} else {
&generics_snip[1..generics_snip.len() - 1]
};
multispan_sugg(
diag,
"consider adding a type parameter",
vec![
(
generics_suggestion_span,
format!(
"<{}{}S: ::std::hash::BuildHasher{}>",
generics_snip,
if generics_snip.is_empty() { "" } else { ", " },
if vis.suggestions.is_empty() {
""
} else {
// request users to add `Default` bound so that generic constructors can be used
" + Default"
},
),
),
(
target.span(),
format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
),
],
);
if !vis.suggestions.is_empty() {
multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
}
}
if !cx.access_levels.is_exported(item.hir_id()) {
return;
}
match item.kind {
ItemKind::Impl(ref impl_) => {
let mut vis = ImplicitHasherTypeVisitor::new(cx);
vis.visit_ty(impl_.self_ty);
for target in &vis.found {
if differing_macro_contexts(item.span, target.span()) {
return;
}
let generics_suggestion_span = impl_.generics.span.substitute_dummy({
let pos = snippet_opt(cx, item.span.until(target.span()))
.and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
if let Some(pos) = pos {
Span::new(pos, pos, item.span.data().ctxt)
} else {
return;
}
});
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
ctr_vis.visit_impl_item(item);
}
span_lint_and_then(
cx,
IMPLICIT_HASHER,
target.span(),
&format!(
"impl for `{}` should be generalized over different hashers",
target.type_name()
),
move |diag| {
suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
},
);
}
},
ItemKind::Fn(ref sig, ref generics, body_id) => {
let body = cx.tcx.hir().body(body_id);
for ty in sig.decl.inputs {
let mut vis = ImplicitHasherTypeVisitor::new(cx);
vis.visit_ty(ty);
for target in &vis.found {
if in_external_macro(cx.sess(), generics.span) {
continue;
}
let generics_suggestion_span = generics.span.substitute_dummy({
let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
.and_then(|snip| {
let i = snip.find("fn")?;
Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
})
.expect("failed to create span for type parameters");
Span::new(pos, pos, item.span.data().ctxt)
});
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
ctr_vis.visit_body(body);
span_lint_and_then(
cx,
IMPLICIT_HASHER,
target.span(),
&format!(
"parameter of type `{}` should be generalized over different hashers",
target.type_name()
),
move |diag| {
suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
},
);
}
}
},
_ => {},
}
}
}
enum ImplicitHasherType<'tcx> {
HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
HashSet(Span, Ty<'tcx>, Cow<'static, str>),
}
impl<'tcx> ImplicitHasherType<'tcx> {
/// Checks that `ty` is a target type without a `BuildHasher`.
fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind {
let params: Vec<_> = path
.segments
.last()
.as_ref()?
.args
.as_ref()?
.args
.iter()
.filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect();
let params_len = params.len();
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 {
Some(ImplicitHasherType::HashMap(
hir_ty.span,
ty,
snippet(cx, params[0].span, "K"),
snippet(cx, params[1].span, "V"),
))
} else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 {
Some(ImplicitHasherType::HashSet(
hir_ty.span,
ty,
snippet(cx, params[0].span, "T"),
))
} else {
None
}
} else {
None
}
}
fn type_name(&self) -> &'static str {
match *self {
ImplicitHasherType::HashMap(..) => "HashMap",
ImplicitHasherType::HashSet(..) => "HashSet",
}
}
fn type_arguments(&self) -> String {
match *self {
ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
}
}
fn ty(&self) -> Ty<'tcx> {
match *self {
ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
}
}
fn span(&self) -> Span {
match *self {
ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
}
}
}
struct ImplicitHasherTypeVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
found: Vec<ImplicitHasherType<'tcx>>,
}
impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
fn new(cx: &'a LateContext<'tcx>) -> Self {
Self { cx, found: vec![] }
}
}
impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
type Map = Map<'tcx>;
fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
if let Some(target) = ImplicitHasherType::new(self.cx, t) {
self.found.push(target);
}
walk_ty(self, t);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
}
/// Looks for default-hasher-dependent constructors like `HashMap::new`.
struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
cx: &'a LateContext<'tcx>,
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
target: &'b ImplicitHasherType<'tcx>,
suggestions: BTreeMap<Span, String>,
}
impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
Self {
cx,
maybe_typeck_results: cx.maybe_typeck_results(),
target,
suggestions: BTreeMap::new(),
}
}
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
type Map = Map<'tcx>;
fn visit_body(&mut self, body: &'tcx Body<'_>) {
let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
walk_body(self, body);
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Call(ref fun, ref args) = e.kind;
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
then {
if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
return;
}
if match_path(ty_path, &paths::HASHMAP) {
if method.ident.name == sym::new {
self.suggestions
.insert(e.span, "HashMap::default()".to_string());
} else if method.ident.name == sym!(with_capacity) {
self.suggestions.insert(
e.span,
format!(
"HashMap::with_capacity_and_hasher({}, Default::default())",
snippet(self.cx, args[0].span, "capacity"),
),
);
}
} else if match_path(ty_path, &paths::HASHSET) {
if method.ident.name == sym::new {
self.suggestions
.insert(e.span, "HashSet::default()".to_string());
} else if method.ident.name == sym!(with_capacity) {
self.suggestions.insert(
e.span,
format!(
"HashSet::with_capacity_and_hasher({}, Default::default())",
snippet(self.cx, args[0].span, "capacity"),
),
);
}
}
}
}
walk_expr(self, e);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
}
}

View File

@ -0,0 +1,221 @@
use std::cmp::Ordering;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, IntTy, UintTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
use rustc_target::abi::LayoutOf;
use crate::consts::{constant, Constant};
use clippy_utils::comparisons::Rel;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{comparisons, sext};
declare_clippy_lint! {
/// **What it does:** Checks for comparisons where the relation is always either
/// true or false, but where one side has been upcast so that the comparison is
/// necessary. Only integer types are checked.
///
/// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
/// will mistakenly imply that it is possible for `x` to be outside the range of
/// `u8`.
///
/// **Known problems:**
/// https://github.com/rust-lang/rust-clippy/issues/886
///
/// **Example:**
/// ```rust
/// let x: u8 = 1;
/// (x as u32) > 300;
/// ```
pub INVALID_UPCAST_COMPARISONS,
pedantic,
"a comparison involving an upcast which is always true or false"
}
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
#[derive(Copy, Clone, Debug, Eq)]
enum FullInt {
S(i128),
U(u128),
}
impl FullInt {
#[allow(clippy::cast_sign_loss)]
#[must_use]
fn cmp_s_u(s: i128, u: u128) -> Ordering {
if s < 0 {
Ordering::Less
} else if u > (i128::MAX as u128) {
Ordering::Greater
} else {
(s as u128).cmp(&u)
}
}
}
impl PartialEq for FullInt {
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
}
}
impl PartialOrd for FullInt {
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(match (self, other) {
(&Self::S(s), &Self::S(o)) => s.cmp(&o),
(&Self::U(s), &Self::U(o)) => s.cmp(&o),
(&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
(&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
})
}
}
impl Ord for FullInt {
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other)
.expect("`partial_cmp` for FullInt can never return `None`")
}
}
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
let cast_ty = cx.typeck_results().expr_ty(expr);
// if it's a cast from i32 to u32 wrapping will invalidate all these checks
if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
return None;
}
match pre_cast_ty.kind() {
ty::Int(int_ty) => Some(match int_ty {
IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
}),
ty::Uint(uint_ty) => Some(match uint_ty {
UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
}),
_ => None,
}
} else {
None
}
}
fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
let val = constant(cx, cx.typeck_results(), expr)?.0;
if let Constant::Int(const_int) = val {
match *cx.typeck_results().expr_ty(expr).kind() {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
}
} else {
None
}
}
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
if let ExprKind::Cast(ref cast_val, _) = expr.kind {
span_lint(
cx,
INVALID_UPCAST_COMPARISONS,
span,
&format!(
"because of the numeric bounds on `{}` prior to casting, this expression is always {}",
snippet(cx, cast_val.span, "the expression"),
if always { "true" } else { "false" },
),
);
}
}
fn upcast_comparison_bounds_err<'tcx>(
cx: &LateContext<'tcx>,
span: Span,
rel: comparisons::Rel,
lhs_bounds: Option<(FullInt, FullInt)>,
lhs: &'tcx Expr<'_>,
rhs: &'tcx Expr<'_>,
invert: bool,
) {
if let Some((lb, ub)) = lhs_bounds {
if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
}
} else if match rel {
Rel::Lt => {
if invert {
norm_rhs_val < lb
} else {
ub < norm_rhs_val
}
},
Rel::Le => {
if invert {
norm_rhs_val <= lb
} else {
ub <= norm_rhs_val
}
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
err_upcast_comparison(cx, span, lhs, true)
} else if match rel {
Rel::Lt => {
if invert {
norm_rhs_val >= ub
} else {
lb >= norm_rhs_val
}
},
Rel::Le => {
if invert {
norm_rhs_val > ub
} else {
lb > norm_rhs_val
}
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
err_upcast_comparison(cx, span, lhs, false)
}
}
}
}
impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
val
} else {
return;
};
let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
}
}
}

View File

@ -164,6 +164,7 @@ mod consts;
mod utils;
// begin lints modules, do not remove this comment, its used in `update_lints`
mod absurd_extreme_comparisons;
mod approx_const;
mod arithmetic;
mod as_conversions;
@ -231,6 +232,7 @@ mod if_let_mutex;
mod if_let_some_result;
mod if_not_else;
mod if_then_some_else_none;
mod implicit_hasher;
mod implicit_return;
mod implicit_saturating_sub;
mod inconsistent_struct_constructor;
@ -241,6 +243,7 @@ mod inherent_to_string;
mod inline_fn_without_body;
mod int_plus_one;
mod integer_division;
mod invalid_upcast_comparisons;
mod items_after_statements;
mod large_const_arrays;
mod large_enum_variant;
@ -559,6 +562,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&utils::internal_lints::PRODUCE_ICE,
#[cfg(feature = "internal-lints")]
&utils::internal_lints::UNNECESSARY_SYMBOL_STR,
&absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
&approx_const::APPROX_CONSTANT,
&arithmetic::FLOAT_ARITHMETIC,
&arithmetic::INTEGER_ARITHMETIC,
@ -683,6 +687,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&if_let_some_result::IF_LET_SOME_RESULT,
&if_not_else::IF_NOT_ELSE,
&if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
&implicit_hasher::IMPLICIT_HASHER,
&implicit_return::IMPLICIT_RETURN,
&implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
@ -696,6 +701,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
&int_plus_one::INT_PLUS_ONE,
&integer_division::INTEGER_DIVISION,
&invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
&items_after_statements::ITEMS_AFTER_STATEMENTS,
&large_const_arrays::LARGE_CONST_ARRAYS,
&large_enum_variant::LARGE_ENUM_VARIANT,
@ -957,11 +963,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&transmute::WRONG_TRANSMUTE,
&transmuting_null::TRANSMUTING_NULL,
&try_err::TRY_ERR,
&types::ABSURD_EXTREME_COMPARISONS,
&types::BORROWED_BOX,
&types::BOX_VEC,
&types::IMPLICIT_HASHER,
&types::INVALID_UPCAST_COMPARISONS,
&types::LINKEDLIST,
&types::OPTION_OPTION,
&types::RC_BUFFER,
@ -1030,7 +1033,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
store.register_late_pass(|| box serde_api::SerdeApi);
let vec_box_size_threshold = conf.vec_box_size_threshold;
store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
let type_complexity_threshold = conf.type_complexity_threshold;
store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
store.register_late_pass(|| box booleans::NonminimalBool);
store.register_late_pass(|| box eq_op::EqOp);
store.register_late_pass(|| box enum_clike::UnportableVariant);
@ -1093,8 +1097,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box main_recursion::MainRecursion::default());
store.register_late_pass(|| box lifetimes::Lifetimes);
store.register_late_pass(|| box entry::HashMapPass);
let type_complexity_threshold = conf.type_complexity_threshold;
store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
store.register_late_pass(|| box minmax::MinMaxPass);
store.register_late_pass(|| box open_options::OpenOptions);
store.register_late_pass(|| box zero_div_zero::ZeroDiv);
@ -1116,8 +1118,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
store.register_late_pass(|| box empty_enum::EmptyEnum);
store.register_late_pass(|| box types::AbsurdExtremeComparisons);
store.register_late_pass(|| box types::InvalidUpcastComparisons);
store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
store.register_late_pass(|| box regex::Regex::default());
store.register_late_pass(|| box copies::CopyAndPaste);
store.register_late_pass(|| box copy_iterator::CopyIterator);
@ -1161,7 +1163,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box infinite_iter::InfiniteIter);
store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
store.register_late_pass(|| box useless_conversion::UselessConversion::default());
store.register_late_pass(|| box types::ImplicitHasher);
store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
store.register_late_pass(|| box double_comparison::DoubleComparisons);
store.register_late_pass(|| box question_mark::QuestionMark);
@ -1374,8 +1376,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&functions::MUST_USE_CANDIDATE),
LintId::of(&functions::TOO_MANY_LINES),
LintId::of(&if_not_else::IF_NOT_ELSE),
LintId::of(&implicit_hasher::IMPLICIT_HASHER),
LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
LintId::of(&invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
@ -1414,8 +1418,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&strings::STRING_ADD_ASSIGN),
LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(&types::IMPLICIT_HASHER),
LintId::of(&types::INVALID_UPCAST_COMPARISONS),
LintId::of(&types::LINKEDLIST),
LintId::of(&types::OPTION_OPTION),
LintId::of(&unicode::NON_ASCII_LITERAL),
@ -1445,6 +1447,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
]);
store.register_group(true, "clippy::all", Some("clippy"), vec![
LintId::of(&absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
LintId::of(&approx_const::APPROX_CONSTANT),
LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
@ -1705,7 +1708,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&transmute::WRONG_TRANSMUTE),
LintId::of(&transmuting_null::TRANSMUTING_NULL),
LintId::of(&try_err::TRY_ERR),
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
LintId::of(&types::BORROWED_BOX),
LintId::of(&types::BOX_VEC),
LintId::of(&types::REDUNDANT_ALLOCATION),
@ -1945,6 +1947,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
]);
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
LintId::of(&absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
LintId::of(&approx_const::APPROX_CONSTANT),
LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
@ -2007,7 +2010,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(&transmute::WRONG_TRANSMUTE),
LintId::of(&transmuting_null::TRANSMUTING_NULL),
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(&unicode::INVISIBLE_CHARACTERS),
LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
use clippy_utils::diagnostics::span_lint;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_ty, NestedVisitorMap, Visitor};
use rustc_hir::{GenericParamKind, TyKind};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_target::spec::abi::Abi;
use super::TYPE_COMPLEXITY;
pub(super) fn check(cx: &LateContext<'_>, ty: &hir::Ty<'_>, type_complexity_threshold: u64) -> bool {
let score = {
let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
visitor.visit_ty(ty);
visitor.score
};
if score > type_complexity_threshold {
span_lint(
cx,
TYPE_COMPLEXITY,
ty.span,
"very complex type used. Consider factoring parts into `type` definitions",
);
true
} else {
false
}
}
/// Walks a type and assigns a complexity score to it.
struct TypeComplexityVisitor {
/// total complexity score of the type
score: u64,
/// current nesting level
nest: u64,
}
impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
type Map = Map<'tcx>;
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
let (add_score, sub_nest) = match ty.kind {
// _, &x and *x have only small overhead; don't mess with nesting level
TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
// the "normal" components of a type: named types, arrays/tuples
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
// function types bring a lot of overhead
TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
TyKind::TraitObject(ref param_bounds, _, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| {
bound
.bound_generic_params
.iter()
.any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
});
if has_lifetime_parameters {
// complex trait bounds like A<'a, 'b>
(50 * self.nest, 1)
} else {
// simple trait bounds like A + B
(20 * self.nest, 0)
}
},
_ => (0, 0),
};
self.score += add_score;
self.nest += sub_nest;
walk_ty(self, ty);
self.nest -= sub_nest;
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
}

View File

@ -5,6 +5,9 @@
extern crate alloc;
use alloc::collections::linked_list::LinkedList;
const C: LinkedList<i32> = LinkedList::new();
static S: LinkedList<i32> = LinkedList::new();
trait Foo {
type Baz = LinkedList<u8>;
fn foo(_: LinkedList<u8>);

View File

@ -1,14 +1,30 @@
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:9:16
--> $DIR/linkedlist.rs:8:10
|
LL | type Baz = LinkedList<u8>;
| ^^^^^^^^^^^^^^
LL | const C: LinkedList<i32> = LinkedList::new();
| ^^^^^^^^^^^^^^^
|
= note: `-D clippy::linkedlist` implied by `-D warnings`
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:10:15
--> $DIR/linkedlist.rs:9:11
|
LL | static S: LinkedList<i32> = LinkedList::new();
| ^^^^^^^^^^^^^^^
|
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/linkedlist.rs:12:16
|
LL | type Baz = LinkedList<u8>;
| ^^^^^^^^^^^^^^
|
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/linkedlist.rs:13:15
|
LL | fn foo(_: LinkedList<u8>);
| ^^^^^^^^^^^^^^
@ -16,7 +32,7 @@ LL | fn foo(_: LinkedList<u8>);
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:11:23
--> $DIR/linkedlist.rs:14:23
|
LL | const BAR: Option<LinkedList<u8>>;
| ^^^^^^^^^^^^^^
@ -24,7 +40,7 @@ LL | const BAR: Option<LinkedList<u8>>;
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:22:15
--> $DIR/linkedlist.rs:25:15
|
LL | fn foo(_: LinkedList<u8>) {}
| ^^^^^^^^^^^^^^
@ -32,7 +48,7 @@ LL | fn foo(_: LinkedList<u8>) {}
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:25:39
--> $DIR/linkedlist.rs:28:39
|
LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
| ^^^^^^^^^^^^^^
@ -40,12 +56,12 @@ LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
= help: a `VecDeque` might work
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/dlist.rs:29:29
--> $DIR/linkedlist.rs:32:29
|
LL | pub fn test_ret() -> Option<LinkedList<u8>> {
| ^^^^^^^^^^^^^^
|
= help: a `VecDeque` might work
error: aborting due to 6 previous errors
error: aborting due to 8 previous errors

View File

@ -1,6 +1,9 @@
#![deny(clippy::option_option)]
#![allow(clippy::unnecessary_wraps)]
const C: Option<Option<i32>> = None;
static S: Option<Option<i32>> = None;
fn input(_: Option<Option<u8>>) {}
fn output() -> Option<Option<u8>> {

View File

@ -1,8 +1,8 @@
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:4:13
--> $DIR/option_option.rs:4:10
|
LL | fn input(_: Option<Option<u8>>) {}
| ^^^^^^^^^^^^^^^^^^
LL | const C: Option<Option<i32>> = None;
| ^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/option_option.rs:1:9
@ -11,58 +11,70 @@ LL | #![deny(clippy::option_option)]
| ^^^^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:6:16
--> $DIR/option_option.rs:5:11
|
LL | static S: Option<Option<i32>> = None;
| ^^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:7:13
|
LL | fn input(_: Option<Option<u8>>) {}
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:9:16
|
LL | fn output() -> Option<Option<u8>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:10:27
--> $DIR/option_option.rs:13:27
|
LL | fn output_nested() -> Vec<Option<Option<u8>>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:15:30
--> $DIR/option_option.rs:18:30
|
LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:20:8
--> $DIR/option_option.rs:23:8
|
LL | x: Option<Option<u8>>,
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:24:23
--> $DIR/option_option.rs:27:23
|
LL | fn struct_fn() -> Option<Option<u8>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:30:22
--> $DIR/option_option.rs:33:22
|
LL | fn trait_fn() -> Option<Option<u8>>;
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:34:11
--> $DIR/option_option.rs:37:11
|
LL | Tuple(Option<Option<u8>>),
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:35:17
--> $DIR/option_option.rs:38:17
|
LL | Struct { x: Option<Option<u8>> },
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:76:14
--> $DIR/option_option.rs:79:14
|
LL | foo: Option<Option<Cow<'a, str>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 10 previous errors
error: aborting due to 12 previous errors

View File

@ -1,5 +1,5 @@
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:7:12
--> $DIR/type_complexity.rs:7:12
|
LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -7,85 +7,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
= note: `-D clippy::type-complexity` implied by `-D warnings`
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:8:12
--> $DIR/type_complexity.rs:8:12
|
LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:11:8
--> $DIR/type_complexity.rs:11:8
|
LL | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:14:11
--> $DIR/type_complexity.rs:14:11
|
LL | struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:17:11
--> $DIR/type_complexity.rs:17:11
|
LL | Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:18:17
--> $DIR/type_complexity.rs:18:17
|
LL | Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:22:14
--> $DIR/type_complexity.rs:22:14
|
LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:23:30
--> $DIR/type_complexity.rs:23:30
|
LL | fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:27:14
--> $DIR/type_complexity.rs:27:14
|
LL | const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:28:14
--> $DIR/type_complexity.rs:28:14
|
LL | type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:29:25
--> $DIR/type_complexity.rs:29:25
|
LL | fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:30:29
--> $DIR/type_complexity.rs:30:29
|
LL | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:33:15
--> $DIR/type_complexity.rs:33:15
|
LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:37:14
--> $DIR/type_complexity.rs:37:14
|
LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:40:13
--> $DIR/type_complexity.rs:40:13
|
LL | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -9,6 +9,8 @@ struct BigStruct([i32; 10000]);
/// The following should trigger the lint
mod should_trigger {
use super::SizedStruct;
const C: Vec<i32> = Vec::new();
static S: Vec<i32> = Vec::new();
struct StructWithVecBox {
sized_type: Vec<SizedStruct>,

View File

@ -9,6 +9,8 @@ struct BigStruct([i32; 10000]);
/// The following should trigger the lint
mod should_trigger {
use super::SizedStruct;
const C: Vec<Box<i32>> = Vec::new();
static S: Vec<Box<i32>> = Vec::new();
struct StructWithVecBox {
sized_type: Vec<Box<SizedStruct>>,

View File

@ -1,28 +1,40 @@
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:14:21
--> $DIR/vec_box_sized.rs:12:14
|
LL | sized_type: Vec<Box<SizedStruct>>,
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
LL | const C: Vec<Box<i32>> = Vec::new();
| ^^^^^^^^^^^^^ help: try: `Vec<i32>`
|
= note: `-D clippy::vec-box` implied by `-D warnings`
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:17:14
--> $DIR/vec_box_sized.rs:13:15
|
LL | static S: Vec<Box<i32>> = Vec::new();
| ^^^^^^^^^^^^^ help: try: `Vec<i32>`
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:16:21
|
LL | sized_type: Vec<Box<SizedStruct>>,
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:19:14
|
LL | struct A(Vec<Box<SizedStruct>>);
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:18:18
--> $DIR/vec_box_sized.rs:20:18
|
LL | struct B(Vec<Vec<Box<(u32)>>>);
| ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
error: `Vec<T>` is already on the heap, the boxing is unnecessary
--> $DIR/vec_box_sized.rs:46:23
--> $DIR/vec_box_sized.rs:48:23
|
LL | pub fn f() -> Vec<Box<S>> {
| ^^^^^^^^^^^ help: try: `Vec<S>`
error: aborting due to 4 previous errors
error: aborting due to 6 previous errors