Auto merge of #84620 - Dylan-DPC:rollup-wkv97im, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #84132 (Ignore nonstandard lldb version strings in compiletest) - #84521 (Reuse modules on `hermit`) - #84563 (Update backtrace to 0.3.57) - #84610 (Update Clippy) - #84613 (move representability checks to rustc_ty_utils) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
83ebb00645
@ -4590,6 +4590,7 @@ dependencies = [
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"rustc_ty_utils",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
@ -18,10 +18,10 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::{Integer, Size, TargetDataLayout};
|
||||
use smallvec::SmallVec;
|
||||
use std::{cmp, fmt, iter};
|
||||
use std::{fmt, iter};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Discr<'tcx> {
|
||||
@ -135,21 +135,6 @@ impl IntTypeExt for attr::IntType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes whether a type is representable. For types that are not
|
||||
/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
|
||||
/// distinguish between types that are recursive with themselves and types that
|
||||
/// contain a different recursive type. These cases can therefore be treated
|
||||
/// differently when reporting errors.
|
||||
///
|
||||
/// The ordering of the cases is significant. They are sorted so that cmp::max
|
||||
/// will keep the "more erroneous" of two values.
|
||||
#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||
pub enum Representability {
|
||||
Representable,
|
||||
ContainsRecursive,
|
||||
SelfRecursive(Vec<Span>),
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Creates a hash of the type `Ty` which will be the same no matter what crate
|
||||
/// context it's calculated within. This is used by the `type_id` intrinsic.
|
||||
@ -870,178 +855,6 @@ impl<'tcx> ty::TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
||||
/// structural recursion. This check is needed for structs and enums.
|
||||
pub fn is_representable(&'tcx self, tcx: TyCtxt<'tcx>, sp: Span) -> Representability {
|
||||
// Iterate until something non-representable is found
|
||||
fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability {
|
||||
iter.fold(Representability::Representable, |r1, r2| match (r1, r2) {
|
||||
(Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => {
|
||||
Representability::SelfRecursive(v1.into_iter().chain(v2).collect())
|
||||
}
|
||||
(r1, r2) => cmp::max(r1, r2),
|
||||
})
|
||||
}
|
||||
|
||||
fn are_inner_types_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
match ty.kind() {
|
||||
Tuple(..) => {
|
||||
// Find non representable
|
||||
fold_repr(ty.tuple_fields().map(|ty| {
|
||||
is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
}))
|
||||
}
|
||||
// Fixed-length vectors.
|
||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
||||
Array(ty, _) => {
|
||||
is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
}
|
||||
Adt(def, substs) => {
|
||||
// Find non representable fields with their spans
|
||||
fold_repr(def.all_fields().map(|field| {
|
||||
let ty = field.ty(tcx, substs);
|
||||
let span = match field
|
||||
.did
|
||||
.as_local()
|
||||
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
|
||||
.and_then(|id| tcx.hir().find(id))
|
||||
{
|
||||
Some(hir::Node::Field(field)) => field.ty.span,
|
||||
_ => sp,
|
||||
};
|
||||
match is_type_structurally_recursive(
|
||||
tcx,
|
||||
span,
|
||||
seen,
|
||||
representable_cache,
|
||||
ty,
|
||||
) {
|
||||
Representability::SelfRecursive(_) => {
|
||||
Representability::SelfRecursive(vec![span])
|
||||
}
|
||||
x => x,
|
||||
}
|
||||
}))
|
||||
}
|
||||
Closure(..) => {
|
||||
// this check is run on type definitions, so we don't expect
|
||||
// to see closure types
|
||||
bug!("requires check invoked on inapplicable type: {:?}", ty)
|
||||
}
|
||||
_ => Representability::Representable,
|
||||
}
|
||||
}
|
||||
|
||||
fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool {
|
||||
match *ty.kind() {
|
||||
Adt(ty_def, _) => ty_def == def,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Does the type `ty` directly (without indirection through a pointer)
|
||||
// contain any types on stack `seen`?
|
||||
fn is_type_structurally_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
|
||||
if let Some(representability) = representable_cache.get(ty) {
|
||||
debug!(
|
||||
"is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
|
||||
ty, sp, representability
|
||||
);
|
||||
return representability.clone();
|
||||
}
|
||||
|
||||
let representability =
|
||||
is_type_structurally_recursive_inner(tcx, sp, seen, representable_cache, ty);
|
||||
|
||||
representable_cache.insert(ty, representability.clone());
|
||||
representability
|
||||
}
|
||||
|
||||
fn is_type_structurally_recursive_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
match ty.kind() {
|
||||
Adt(def, _) => {
|
||||
{
|
||||
// Iterate through stack of previously seen types.
|
||||
let mut iter = seen.iter();
|
||||
|
||||
// The first item in `seen` is the type we are actually curious about.
|
||||
// We want to return SelfRecursive if this type contains itself.
|
||||
// It is important that we DON'T take generic parameters into account
|
||||
// for this check, so that Bar<T> in this example counts as SelfRecursive:
|
||||
//
|
||||
// struct Foo;
|
||||
// struct Bar<T> { x: Bar<Foo> }
|
||||
|
||||
if let Some(&seen_type) = iter.next() {
|
||||
if same_struct_or_enum(seen_type, *def) {
|
||||
debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty);
|
||||
return Representability::SelfRecursive(vec![sp]);
|
||||
}
|
||||
}
|
||||
|
||||
// We also need to know whether the first item contains other types
|
||||
// that are structurally recursive. If we don't catch this case, we
|
||||
// will recurse infinitely for some inputs.
|
||||
//
|
||||
// It is important that we DO take generic parameters into account
|
||||
// here, so that code like this is considered SelfRecursive, not
|
||||
// ContainsRecursive:
|
||||
//
|
||||
// struct Foo { Option<Option<Foo>> }
|
||||
|
||||
for &seen_type in iter {
|
||||
if ty::TyS::same_type(ty, seen_type) {
|
||||
debug!("ContainsRecursive: {:?} contains {:?}", seen_type, ty);
|
||||
return Representability::ContainsRecursive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For structs and enums, track all previously seen types by pushing them
|
||||
// onto the 'seen' stack.
|
||||
seen.push(ty);
|
||||
let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty);
|
||||
seen.pop();
|
||||
out
|
||||
}
|
||||
_ => {
|
||||
// No need to push in other cases.
|
||||
are_inner_types_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("is_type_representable: {:?}", self);
|
||||
|
||||
// To avoid a stack overflow when checking an enum variant or struct that
|
||||
// contains a different, structurally recursive type, maintain a stack
|
||||
// of seen types and check recursion for each of them (issues #3008, #3779).
|
||||
let mut seen: Vec<Ty<'_>> = Vec::new();
|
||||
let mut representable_cache = FxHashMap::default();
|
||||
let r = is_type_structurally_recursive(tcx, sp, &mut seen, &mut representable_cache, self);
|
||||
debug!("is_type_representable: {:?} is {:?}", self, r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Peel off all reference types in this type until there are none left.
|
||||
///
|
||||
/// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`.
|
||||
|
@ -20,6 +20,7 @@ use rustc_middle::ty::query::Providers;
|
||||
mod common_traits;
|
||||
pub mod instance;
|
||||
mod needs_drop;
|
||||
pub mod representability;
|
||||
mod ty;
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
186
compiler/rustc_ty_utils/src/representability.rs
Normal file
186
compiler/rustc_ty_utils/src/representability.rs
Normal file
@ -0,0 +1,186 @@
|
||||
//! Check whether a type is representable.
|
||||
use rustc_data_structures::stable_map::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use std::cmp;
|
||||
|
||||
/// Describes whether a type is representable. For types that are not
|
||||
/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
|
||||
/// distinguish between types that are recursive with themselves and types that
|
||||
/// contain a different recursive type. These cases can therefore be treated
|
||||
/// differently when reporting errors.
|
||||
///
|
||||
/// The ordering of the cases is significant. They are sorted so that cmp::max
|
||||
/// will keep the "more erroneous" of two values.
|
||||
#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||
pub enum Representability {
|
||||
Representable,
|
||||
ContainsRecursive,
|
||||
SelfRecursive(Vec<Span>),
|
||||
}
|
||||
|
||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
||||
/// structural recursion. This check is needed for structs and enums.
|
||||
pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
|
||||
debug!("is_type_representable: {:?}", ty);
|
||||
// To avoid a stack overflow when checking an enum variant or struct that
|
||||
// contains a different, structurally recursive type, maintain a stack
|
||||
// of seen types and check recursion for each of them (issues #3008, #3779).
|
||||
let mut seen: Vec<Ty<'_>> = Vec::new();
|
||||
let mut representable_cache = FxHashMap::default();
|
||||
let r = is_type_structurally_recursive(tcx, sp, &mut seen, &mut representable_cache, ty);
|
||||
debug!("is_type_representable: {:?} is {:?}", ty, r);
|
||||
r
|
||||
}
|
||||
|
||||
// Iterate until something non-representable is found
|
||||
fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability {
|
||||
iter.fold(Representability::Representable, |r1, r2| match (r1, r2) {
|
||||
(Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => {
|
||||
Representability::SelfRecursive(v1.into_iter().chain(v2).collect())
|
||||
}
|
||||
(r1, r2) => cmp::max(r1, r2),
|
||||
})
|
||||
}
|
||||
|
||||
fn are_inner_types_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
match ty.kind() {
|
||||
ty::Tuple(..) => {
|
||||
// Find non representable
|
||||
fold_repr(
|
||||
ty.tuple_fields().map(|ty| {
|
||||
is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
}),
|
||||
)
|
||||
}
|
||||
// Fixed-length vectors.
|
||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
||||
ty::Array(ty, _) => is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty),
|
||||
ty::Adt(def, substs) => {
|
||||
// Find non representable fields with their spans
|
||||
fold_repr(def.all_fields().map(|field| {
|
||||
let ty = field.ty(tcx, substs);
|
||||
let span = match field
|
||||
.did
|
||||
.as_local()
|
||||
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
|
||||
.and_then(|id| tcx.hir().find(id))
|
||||
{
|
||||
Some(hir::Node::Field(field)) => field.ty.span,
|
||||
_ => sp,
|
||||
};
|
||||
match is_type_structurally_recursive(tcx, span, seen, representable_cache, ty) {
|
||||
Representability::SelfRecursive(_) => {
|
||||
Representability::SelfRecursive(vec![span])
|
||||
}
|
||||
x => x,
|
||||
}
|
||||
}))
|
||||
}
|
||||
ty::Closure(..) => {
|
||||
// this check is run on type definitions, so we don't expect
|
||||
// to see closure types
|
||||
bug!("requires check invoked on inapplicable type: {:?}", ty)
|
||||
}
|
||||
_ => Representability::Representable,
|
||||
}
|
||||
}
|
||||
|
||||
fn same_adt<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool {
|
||||
match *ty.kind() {
|
||||
ty::Adt(ty_def, _) => ty_def == def,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Does the type `ty` directly (without indirection through a pointer)
|
||||
// contain any types on stack `seen`?
|
||||
fn is_type_structurally_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
|
||||
if let Some(representability) = representable_cache.get(ty) {
|
||||
debug!(
|
||||
"is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
|
||||
ty, sp, representability
|
||||
);
|
||||
return representability.clone();
|
||||
}
|
||||
|
||||
let representability =
|
||||
is_type_structurally_recursive_inner(tcx, sp, seen, representable_cache, ty);
|
||||
|
||||
representable_cache.insert(ty, representability.clone());
|
||||
representability
|
||||
}
|
||||
|
||||
fn is_type_structurally_recursive_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Representability {
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
{
|
||||
// Iterate through stack of previously seen types.
|
||||
let mut iter = seen.iter();
|
||||
|
||||
// The first item in `seen` is the type we are actually curious about.
|
||||
// We want to return SelfRecursive if this type contains itself.
|
||||
// It is important that we DON'T take generic parameters into account
|
||||
// for this check, so that Bar<T> in this example counts as SelfRecursive:
|
||||
//
|
||||
// struct Foo;
|
||||
// struct Bar<T> { x: Bar<Foo> }
|
||||
|
||||
if let Some(&seen_adt) = iter.next() {
|
||||
if same_adt(seen_adt, *def) {
|
||||
debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
|
||||
return Representability::SelfRecursive(vec![sp]);
|
||||
}
|
||||
}
|
||||
|
||||
// We also need to know whether the first item contains other types
|
||||
// that are structurally recursive. If we don't catch this case, we
|
||||
// will recurse infinitely for some inputs.
|
||||
//
|
||||
// It is important that we DO take generic parameters into account
|
||||
// here, so that code like this is considered SelfRecursive, not
|
||||
// ContainsRecursive:
|
||||
//
|
||||
// struct Foo { Option<Option<Foo>> }
|
||||
|
||||
for &seen_adt in iter {
|
||||
if ty::TyS::same_type(ty, seen_adt) {
|
||||
debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty);
|
||||
return Representability::ContainsRecursive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For structs and enums, track all previously seen types by pushing them
|
||||
// onto the 'seen' stack.
|
||||
seen.push(ty);
|
||||
let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty);
|
||||
seen.pop();
|
||||
out
|
||||
}
|
||||
_ => {
|
||||
// No need to push in other cases.
|
||||
are_inner_types_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
}
|
||||
}
|
||||
}
|
@ -26,3 +26,4 @@ rustc_span = { path = "../rustc_span" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
rustc_ty_utils = { path = "../rustc_ty_utils" }
|
||||
|
@ -15,7 +15,7 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::layout::MAX_SIMD_LANES;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||
@ -25,6 +25,7 @@ use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
use rustc_ty_utils::representability::{self, Representability};
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
@ -1188,7 +1189,7 @@ pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalD
|
||||
// recursive type. It is only necessary to throw an error on those that
|
||||
// contain themselves. For case 2, there must be an inner type that will be
|
||||
// caught by case 1.
|
||||
match rty.is_representable(tcx, sp) {
|
||||
match representability::ty_is_representable(tcx, rty, sp) {
|
||||
Representability::SelfRecursive(spans) => {
|
||||
recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
|
||||
return false;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 710fc18ddcb6c7677b3c96359abb35da37f2a488
|
||||
Subproject commit 221483ebaf45df5c956adffee2d4024e7c3b96b8
|
@ -1,47 +0,0 @@
|
||||
use crate::mem;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct IoSlice<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> IoSlice<'a> {
|
||||
#[inline]
|
||||
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
|
||||
IoSlice(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn advance(&mut self, n: usize) {
|
||||
self.0 = &self.0[n..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IoSliceMut<'a>(&'a mut [u8]);
|
||||
|
||||
impl<'a> IoSliceMut<'a> {
|
||||
#[inline]
|
||||
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
|
||||
IoSliceMut(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn advance(&mut self, n: usize) {
|
||||
let slice = mem::replace(&mut self.0, &mut []);
|
||||
let (_, remaining) = slice.split_at_mut(n);
|
||||
self.0 = remaining;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
self.0
|
||||
}
|
||||
}
|
@ -26,11 +26,13 @@ pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
#[path = "../unsupported/io.rs"]
|
||||
pub mod io;
|
||||
pub mod memchr;
|
||||
pub mod mutex;
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
#[path = "../unix/path.rs"]
|
||||
pub mod path;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
@ -40,6 +42,7 @@ pub mod rwlock;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local_dtor;
|
||||
#[path = "../unsupported/thread_local_key.rs"]
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
use crate::ffi::OsStr;
|
||||
use crate::path::Prefix;
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
|
||||
None
|
||||
}
|
||||
|
||||
pub const MAIN_SEP_STR: &str = "/";
|
||||
pub const MAIN_SEP: char = '/';
|
@ -1,26 +0,0 @@
|
||||
pub type Key = usize;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set(_key: Key, _value: *mut u8) {
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get(_key: Key) -> *mut u8 {
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn destroy(_key: Key) {
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn requires_synchronized_create() -> bool {
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::meets_msrv;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
|
||||
@ -12,10 +12,8 @@ use rustc_semver::RustcVersion;
|
||||
|
||||
use super::PTR_AS_PTR;
|
||||
|
||||
const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0);
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option<RustcVersion>) {
|
||||
if !meets_msrv(msrv.as_ref(), &PTR_AS_PTR_MSRV) {
|
||||
if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{meets_msrv, SpanlessEq};
|
||||
use clippy_utils::{meets_msrv, msrvs, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
@ -12,8 +12,6 @@ use rustc_middle::lint::in_external_macro;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for explicit bounds checking when casting.
|
||||
///
|
||||
@ -58,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &CHECKED_CONVERSIONS_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::paths::INTO;
|
||||
use clippy_utils::{match_def_path, meets_msrv};
|
||||
use clippy_utils::{match_def_path, meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const FROM_OVER_INTO_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
|
||||
///
|
||||
@ -57,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
|
||||
|
||||
impl LateLintPass<'_> for FromOverInto {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &FROM_OVER_INTO_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet_with_macro_callsite;
|
||||
use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv};
|
||||
use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -9,8 +9,6 @@ use rustc_middle::lint::in_external_macro;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const IF_THEN_SOME_ELSE_NONE_MSRV: RustcVersion = RustcVersion::new(1, 50, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for if-else that could be written to `bool::then`.
|
||||
///
|
||||
@ -59,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
|
||||
|
||||
impl LateLintPass<'_> for IfThenSomeElseNone {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1077,7 +1077,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
|
||||
store.register_late_pass(move || box use_self::UseSelf::new(msrv));
|
||||
store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
|
||||
store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv));
|
||||
store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
|
||||
store.register_late_pass(move || box casts::Casts::new(msrv));
|
||||
store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
|
||||
|
||||
|
@ -14,8 +14,14 @@ pub(super) fn check<'tcx>(
|
||||
body: &'tcx Expr<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
) {
|
||||
let arg_expr = match arg.kind {
|
||||
ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
|
||||
ExprKind::MethodCall(method, _, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => {
|
||||
&args[0]
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
if_chain! {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, arg_expr) = arg.kind;
|
||||
if let PatKind::Binding(.., target, _) = pat.kind;
|
||||
if let ExprKind::Array([arg_expression]) = arg_expr.kind;
|
||||
if let ExprKind::Path(ref list_item) = arg_expression.kind;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::meets_msrv;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
|
||||
use rustc_errors::Applicability;
|
||||
@ -10,8 +10,6 @@ use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
|
||||
///
|
||||
@ -76,7 +74,7 @@ impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
|
||||
|
||||
impl EarlyLintPass for ManualNonExhaustive {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use crate::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths};
|
||||
use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::def::Res;
|
||||
@ -17,8 +17,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::Span;
|
||||
|
||||
const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:**
|
||||
/// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
|
||||
@ -74,7 +72,7 @@ enum StripKind {
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,15 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
then {
|
||||
let reindented_or_body =
|
||||
reindent_multiline(or_body_snippet.into(), true, Some(indent));
|
||||
|
||||
let suggestion = if scrutinee.span.from_expansion() {
|
||||
// we don't want parenthesis around macro, e.g. `(some_macro!()).unwrap_or(0)`
|
||||
sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
|
||||
}
|
||||
else {
|
||||
sugg::Sugg::hir(cx, scrutinee, "..").maybe_par()
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_UNWRAP_OR, expr.span,
|
||||
@ -119,7 +128,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
"replace with",
|
||||
format!(
|
||||
"{}.unwrap_or({})",
|
||||
sugg::Sugg::hir(cx, scrutinee, "..").maybe_par(),
|
||||
suggestion,
|
||||
reindented_or_body,
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
|
@ -7,8 +7,9 @@ use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
|
||||
use clippy_utils::visitors::LocalUsedVisitor;
|
||||
use clippy_utils::{
|
||||
get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, path_to_local,
|
||||
path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs,
|
||||
get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, msrvs,
|
||||
path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
|
||||
strip_pat_refs,
|
||||
};
|
||||
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||
use if_chain::if_chain;
|
||||
@ -578,8 +579,6 @@ impl_lint_pass!(Matches => [
|
||||
MATCH_SAME_ARMS,
|
||||
]);
|
||||
|
||||
const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
|
||||
@ -588,7 +587,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
|
||||
redundant_pattern_match::check(cx, expr);
|
||||
|
||||
if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
|
||||
if !check_match_like_matches(cx, expr) {
|
||||
lint_match_arms(cx, expr);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, paths};
|
||||
use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -256,8 +256,6 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
|
||||
}
|
||||
}
|
||||
|
||||
const MEM_REPLACE_WITH_DEFAULT_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
|
||||
|
||||
pub struct MemReplace {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
@ -281,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
|
||||
then {
|
||||
check_replace_option_with_none(cx, src, dest, expr.span);
|
||||
check_replace_with_uninit(cx, src, dest, expr.span);
|
||||
if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) {
|
||||
check_replace_with_default(cx, src, dest, expr.span);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,30 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
|
||||
use clippy_utils::{is_trait_method, meets_msrv, msrvs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use super::CLONED_INSTEAD_OF_COPIED;
|
||||
|
||||
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) {
|
||||
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) {
|
||||
let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
|
||||
let inner_ty = match recv_ty.kind() {
|
||||
// `Option<T>` -> `T`
|
||||
ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => subst.type_at(0),
|
||||
_ if is_trait_method(cx, expr, sym::Iterator) => match get_iterator_item_ty(cx, recv_ty) {
|
||||
// <T as Iterator>::Item
|
||||
Some(ty) => ty,
|
||||
_ => return,
|
||||
ty::Adt(adt, subst)
|
||||
if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) =>
|
||||
{
|
||||
subst.type_at(0)
|
||||
},
|
||||
_ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => {
|
||||
match get_iterator_item_ty(cx, recv_ty) {
|
||||
// <T as Iterator>::Item
|
||||
Some(ty) => ty,
|
||||
_ => return,
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{is_trait_method, meets_msrv};
|
||||
use clippy_utils::{is_trait_method, meets_msrv, msrvs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -9,8 +9,6 @@ use rustc_span::sym;
|
||||
|
||||
use super::FILTER_MAP_NEXT;
|
||||
|
||||
const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0);
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
@ -19,7 +17,7 @@ pub(super) fn check<'tcx>(
|
||||
msrv: Option<&RustcVersion>,
|
||||
) {
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) {
|
||||
if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::meets_msrv;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -11,8 +11,6 @@ use rustc_span::symbol::sym;
|
||||
|
||||
use super::MAP_UNWRAP_OR;
|
||||
|
||||
const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
|
||||
|
||||
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
|
||||
/// Return true if lint triggered
|
||||
pub(super) fn check<'tcx>(
|
||||
@ -23,13 +21,14 @@ pub(super) fn check<'tcx>(
|
||||
unwrap_arg: &'tcx hir::Expr<'_>,
|
||||
msrv: Option<&RustcVersion>,
|
||||
) -> bool {
|
||||
if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) {
|
||||
return false;
|
||||
}
|
||||
// lint if the caller of `map()` is an `Option`
|
||||
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
|
||||
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
|
||||
|
||||
if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if is_option || is_result {
|
||||
// Don't make a suggestion that may fail to compile due to mutably borrowing
|
||||
// the same variable twice.
|
||||
|
@ -1959,7 +1959,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
||||
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
|
||||
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
|
||||
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
|
||||
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span),
|
||||
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
|
||||
("collect", []) => match method_call!(recv) {
|
||||
Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
|
||||
Some(("map", [m_recv, m_arg], _)) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks};
|
||||
use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -12,8 +12,6 @@ use rustc_span::sym;
|
||||
|
||||
use super::OPTION_AS_REF_DEREF;
|
||||
|
||||
const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
|
||||
|
||||
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
@ -23,7 +21,7 @@ pub(super) fn check<'tcx>(
|
||||
is_mut: bool,
|
||||
msrv: Option<&RustcVersion>,
|
||||
) {
|
||||
if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
|
||||
if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,7 @@ pub(super) fn derefs_to_slice<'tcx>(
|
||||
ty::Slice(_) => true,
|
||||
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
|
||||
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type),
|
||||
ty::Array(_, size) => size
|
||||
.try_eval_usize(cx.tcx, cx.param_env)
|
||||
.map_or(false, |size| size < 32),
|
||||
ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(),
|
||||
ty::Ref(_, inner, _) => may_slice(cx, inner),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
|
||||
use clippy_utils::ty::has_drop;
|
||||
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method};
|
||||
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
|
||||
@ -12,8 +12,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
|
||||
const MISSING_CONST_FOR_FN_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:**
|
||||
///
|
||||
@ -97,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,13 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_lang_ctor;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{differing_macro_contexts, meets_msrv};
|
||||
use clippy_utils::{differing_macro_contexts, is_lang_ctor};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionSome, ResultOk};
|
||||
use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -63,21 +61,7 @@ declare_clippy_lint! {
|
||||
"Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
|
||||
}
|
||||
|
||||
const NEEDLESS_QUESTION_MARK_RESULT_MSRV: RustcVersion = RustcVersion::new(1, 13, 0);
|
||||
const NEEDLESS_QUESTION_MARK_OPTION_MSRV: RustcVersion = RustcVersion::new(1, 22, 0);
|
||||
|
||||
pub struct NeedlessQuestionMark {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl NeedlessQuestionMark {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
|
||||
declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SomeOkCall<'a> {
|
||||
@ -111,7 +95,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if let Some(ok_some_call) = is_some_or_ok_call(self, cx, e) {
|
||||
if let Some(ok_some_call) = is_some_or_ok_call(cx, e) {
|
||||
emit_lint(cx, &ok_some_call);
|
||||
}
|
||||
}
|
||||
@ -127,14 +111,12 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
||||
|
||||
if_chain! {
|
||||
if let Some(expr) = expr_opt;
|
||||
if let Some(ok_some_call) = is_some_or_ok_call(self, cx, expr);
|
||||
if let Some(ok_some_call) = is_some_or_ok_call(cx, expr);
|
||||
then {
|
||||
emit_lint(cx, &ok_some_call);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
|
||||
@ -153,11 +135,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
|
||||
);
|
||||
}
|
||||
|
||||
fn is_some_or_ok_call<'a>(
|
||||
nqml: &NeedlessQuestionMark,
|
||||
cx: &'a LateContext<'_>,
|
||||
expr: &'a Expr<'_>,
|
||||
) -> Option<SomeOkCall<'a>> {
|
||||
fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> {
|
||||
if_chain! {
|
||||
// Check outer expression matches CALL_IDENT(ARGUMENT) format
|
||||
if let ExprKind::Call(path, args) = &expr.kind;
|
||||
@ -188,8 +166,7 @@ fn is_some_or_ok_call<'a>(
|
||||
let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type);
|
||||
|
||||
// Check for Option MSRV
|
||||
let meets_option_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV);
|
||||
if outer_is_some && inner_is_some && meets_option_msrv {
|
||||
if outer_is_some && inner_is_some {
|
||||
return Some(SomeOkCall::SomeCall(expr, inner_expr));
|
||||
}
|
||||
|
||||
@ -202,8 +179,7 @@ fn is_some_or_ok_call<'a>(
|
||||
let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);
|
||||
|
||||
// Must meet Result MSRV
|
||||
let meets_result_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV);
|
||||
if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv {
|
||||
if outer_is_result && inner_is_result && does_not_call_from {
|
||||
return Some(SomeOkCall::OkCall(expr, inner_expr));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path};
|
||||
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path};
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
@ -159,8 +159,6 @@ declare_clippy_lint! {
|
||||
"manually reimplementing {`Range`, `RangeInclusive`}`::contains`"
|
||||
}
|
||||
|
||||
const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0);
|
||||
|
||||
pub struct Ranges {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
@ -187,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
|
||||
check_range_zip_with_len(cx, path, args, expr.span);
|
||||
},
|
||||
ExprKind::Binary(ref op, l, r) => {
|
||||
if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) {
|
||||
check_possible_range_contains(cx, op.node, l, r, expr);
|
||||
}
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::meets_msrv;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
@ -7,8 +7,6 @@ use rustc_middle::lint::in_external_macro;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for fields in struct literals where shorthands
|
||||
/// could be used.
|
||||
@ -52,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
|
||||
|
||||
impl EarlyLintPass for RedundantFieldNames {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_FIELD_NAMES_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::meets_msrv;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for constants and statics with an explicit `'static` lifetime.
|
||||
///
|
||||
@ -100,7 +98,7 @@ impl RedundantStaticLifetimes {
|
||||
|
||||
impl EarlyLintPass for RedundantStaticLifetimes {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::in_macro;
|
||||
use rustc_ast::{ptr::P, Crate, Item, ItemKind, ModKind, UseTreeKind};
|
||||
use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -60,8 +60,21 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
|
||||
// ```
|
||||
let mut single_use_usages = Vec::new();
|
||||
|
||||
// keep track of macros defined in the module as we don't want it to trigger on this (#7106)
|
||||
// ```rust,ignore
|
||||
// macro_rules! foo { () => {} };
|
||||
// pub(crate) use foo;
|
||||
// ```
|
||||
let mut macros = Vec::new();
|
||||
|
||||
for item in items {
|
||||
track_uses(cx, &item, &mut imports_reused_with_self, &mut single_use_usages);
|
||||
track_uses(
|
||||
cx,
|
||||
&item,
|
||||
&mut imports_reused_with_self,
|
||||
&mut single_use_usages,
|
||||
&mut macros,
|
||||
);
|
||||
}
|
||||
|
||||
for single_use in &single_use_usages {
|
||||
@ -96,6 +109,7 @@ fn track_uses(
|
||||
item: &Item,
|
||||
imports_reused_with_self: &mut Vec<Symbol>,
|
||||
single_use_usages: &mut Vec<(Symbol, Span, bool)>,
|
||||
macros: &mut Vec<Symbol>,
|
||||
) {
|
||||
if in_macro(item.span) || item.vis.kind.is_pub() {
|
||||
return;
|
||||
@ -105,14 +119,22 @@ fn track_uses(
|
||||
ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
|
||||
check_mod(cx, &items);
|
||||
},
|
||||
ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
|
||||
macros.push(item.ident.name);
|
||||
},
|
||||
ItemKind::Use(use_tree) => {
|
||||
let segments = &use_tree.prefix.segments;
|
||||
|
||||
let should_report =
|
||||
|name: &Symbol| !macros.contains(name) || matches!(item.vis.kind, VisibilityKind::Inherited);
|
||||
|
||||
// keep track of `use some_module;` usages
|
||||
if segments.len() == 1 {
|
||||
if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
|
||||
let ident = &segments[0].ident;
|
||||
single_use_usages.push((ident.name, item.span, true));
|
||||
let name = segments[0].ident.name;
|
||||
if should_report(&name) {
|
||||
single_use_usages.push((name, item.span, true));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -124,8 +146,10 @@ fn track_uses(
|
||||
let segments = &tree.0.prefix.segments;
|
||||
if segments.len() == 1 {
|
||||
if let UseTreeKind::Simple(None, _, _) = tree.0.kind {
|
||||
let ident = &segments[0].ident;
|
||||
single_use_usages.push((ident.name, tree.0.span, false));
|
||||
let name = segments[0].ident.name;
|
||||
if should_report(&name) {
|
||||
single_use_usages.push((name, tree.0.span, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
|
||||
|
||||
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::over;
|
||||
use clippy_utils::{
|
||||
ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path},
|
||||
meets_msrv,
|
||||
};
|
||||
use clippy_utils::{meets_msrv, msrvs, over};
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
|
||||
@ -54,8 +51,6 @@ declare_clippy_lint! {
|
||||
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
|
||||
}
|
||||
|
||||
const UNNESTED_OR_PATTERNS_MSRV: RustcVersion = RustcVersion::new(1, 53, 0);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UnnestedOrPatterns {
|
||||
msrv: Option<RustcVersion>,
|
||||
@ -72,13 +67,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
|
||||
|
||||
impl EarlyLintPass for UnnestedOrPatterns {
|
||||
fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
|
||||
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
|
||||
lint_unnested_or_patterns(cx, &a.pat);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
|
||||
if let ast::ExprKind::Let(pat, _) = &e.kind {
|
||||
lint_unnested_or_patterns(cx, pat);
|
||||
}
|
||||
@ -86,13 +81,13 @@ impl EarlyLintPass for UnnestedOrPatterns {
|
||||
}
|
||||
|
||||
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
|
||||
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
|
||||
lint_unnested_or_patterns(cx, &p.pat);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
|
||||
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
|
||||
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
|
||||
lint_unnested_or_patterns(cx, &l.pat);
|
||||
}
|
||||
}
|
||||
|
@ -47,25 +47,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
|
||||
func.kind,
|
||||
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
|
||||
) {
|
||||
check_method_call(cx, &args[0], expr);
|
||||
check_map_error(cx, &args[0], expr);
|
||||
}
|
||||
} else {
|
||||
check_method_call(cx, res, expr);
|
||||
check_map_error(cx, res, expr);
|
||||
}
|
||||
},
|
||||
|
||||
hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() {
|
||||
"expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
|
||||
check_method_call(cx, &args[0], expr);
|
||||
check_map_error(cx, &args[0], expr);
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
|
||||
let mut call = call;
|
||||
while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
|
||||
if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
|
||||
call = &args[0];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
check_method_call(cx, call, expr);
|
||||
}
|
||||
|
||||
fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
|
||||
if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind {
|
||||
let symbol = &*path.ident.as_str();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{in_macro, meets_msrv};
|
||||
use clippy_utils::{in_macro, meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -62,8 +62,6 @@ pub struct UseSelf {
|
||||
stack: Vec<StackItem>,
|
||||
}
|
||||
|
||||
const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
|
||||
|
||||
impl UseSelf {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
@ -236,7 +234,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
||||
}
|
||||
|
||||
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
|
||||
if in_macro(hir_ty.span) | in_impl(cx, hir_ty) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
|
||||
if in_macro(hir_ty.span)
|
||||
|| in_impl(cx, hir_ty)
|
||||
|| !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -288,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
||||
}
|
||||
}
|
||||
|
||||
if in_macro(expr.span) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
|
||||
if in_macro(expr.span) || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ macro_rules! define_Conf {
|
||||
|
||||
pub use self::helpers::Conf;
|
||||
define_Conf! {
|
||||
/// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. The minimum rust version that the project supports
|
||||
/// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR. The minimum rust version that the project supports
|
||||
(msrv, "msrv": Option<String>, None),
|
||||
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
(blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
|
||||
|
@ -38,6 +38,7 @@ pub mod diagnostics;
|
||||
pub mod eager_or_lazy;
|
||||
pub mod higher;
|
||||
mod hir_utils;
|
||||
pub mod msrvs;
|
||||
pub mod numeric_literal;
|
||||
pub mod paths;
|
||||
pub mod ptr;
|
||||
|
29
src/tools/clippy/clippy_utils/src/msrvs.rs
Normal file
29
src/tools/clippy/clippy_utils/src/msrvs.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use rustc_semver::RustcVersion;
|
||||
|
||||
macro_rules! msrv_aliases {
|
||||
($($major:literal,$minor:literal,$patch:literal {
|
||||
$($name:ident),* $(,)?
|
||||
})*) => {
|
||||
$($(
|
||||
pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch);
|
||||
)*)*
|
||||
};
|
||||
}
|
||||
|
||||
// names may refer to stabilized feature flags or library items
|
||||
msrv_aliases! {
|
||||
1,53,0 { OR_PATTERNS }
|
||||
1,50,0 { BOOL_THEN }
|
||||
1,46,0 { CONST_IF_MATCH }
|
||||
1,45,0 { STR_STRIP_PREFIX }
|
||||
1,42,0 { MATCHES_MACRO }
|
||||
1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
|
||||
1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
|
||||
1,38,0 { POINTER_CAST }
|
||||
1,37,0 { TYPE_ALIAS_ENUM_VARIANTS }
|
||||
1,36,0 { ITERATOR_COPIED }
|
||||
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
|
||||
1,34,0 { TRY_FROM }
|
||||
1,30,0 { ITERATOR_FIND_MAP }
|
||||
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
|
||||
}
|
@ -364,7 +364,7 @@ fn check_terminator(
|
||||
|
||||
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool {
|
||||
rustc_mir::const_eval::is_const_fn(tcx, def_id)
|
||||
&& if let Some(const_stab) = tcx.lookup_const_stability(def_id) {
|
||||
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
|
||||
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
|
||||
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
|
||||
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
|
||||
@ -375,10 +375,8 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> b
|
||||
.expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"),
|
||||
)
|
||||
} else {
|
||||
// `rustc_mir::const_eval::is_const_fn` should return false for unstably const functions.
|
||||
unreachable!();
|
||||
// Unstable const fn with the feature enabled.
|
||||
msrv.is_none()
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -390,17 +390,23 @@ pass.
|
||||
|
||||
## Specifying the lint's minimum supported Rust version (MSRV)
|
||||
|
||||
Projects supporting older versions of Rust would need to disable a lint if it
|
||||
targets features present in later versions. Support for this can be added by
|
||||
specifying an MSRV in your lint like so,
|
||||
Sometimes a lint makes suggestions that require a certain version of Rust. For example, the `manual_strip` lint suggests
|
||||
using `str::strip_prefix` and `str::strip_suffix` which is only available after Rust 1.45. In such cases, you need to
|
||||
ensure that the MSRV configured for the project is >= the MSRV of the required Rust feature. If multiple features are
|
||||
required, just use the one with a lower MSRV.
|
||||
|
||||
First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`](/clippy_utils/src/msrvs.rs). This can be
|
||||
accessed later as `msrvs::STR_STRIP_PREFIX`, for example.
|
||||
|
||||
```rust
|
||||
const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0);
|
||||
msrv_aliases! {
|
||||
..
|
||||
1,45,0 { STR_STRIP_PREFIX }
|
||||
}
|
||||
```
|
||||
|
||||
The project's MSRV will also have to be an attribute in the lint so you'll have
|
||||
to add a struct and constructor for your lint. The project's MSRV needs to be
|
||||
passed when the lint is registered in `lib.rs`
|
||||
In order to access the project-configured MSRV, you need to have an `msrv` field in the LintPass struct, and a
|
||||
constructor to initialize the field. The `msrv` value is passed to the constructor in `clippy_lints/lib.rs`.
|
||||
|
||||
```rust
|
||||
pub struct ManualStrip {
|
||||
@ -415,11 +421,11 @@ impl ManualStrip {
|
||||
}
|
||||
```
|
||||
|
||||
The project's MSRV can then be matched against the lint's `msrv` in the LintPass
|
||||
The project's MSRV can then be matched against the feature MSRV in the LintPass
|
||||
using the `meets_msrv` utility function.
|
||||
|
||||
``` rust
|
||||
if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
@ -22,9 +22,16 @@ use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver";
|
||||
#[cfg(not(windows))]
|
||||
const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy";
|
||||
|
||||
#[cfg(windows)]
|
||||
const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver.exe";
|
||||
#[cfg(windows)]
|
||||
const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy.exe";
|
||||
|
||||
const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
|
||||
const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
|
||||
|
||||
|
14
src/tools/clippy/tests/ui/crashes/ice-7126.rs
Normal file
14
src/tools/clippy/tests/ui/crashes/ice-7126.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// This test requires a feature gated const fn and will stop working in the future.
|
||||
|
||||
#![feature(const_btree_new)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
struct Foo(BTreeMap<i32, i32>);
|
||||
impl Foo {
|
||||
fn new() -> Self {
|
||||
Self(BTreeMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -19,4 +19,8 @@ fn main() {
|
||||
let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
|
||||
.to_bytes().to_vec();
|
||||
}
|
||||
|
||||
// Issue #6808
|
||||
let arr: [u8; 64] = [0; 64];
|
||||
let _: Vec<_> = arr.to_vec();
|
||||
}
|
||||
|
@ -22,4 +22,8 @@ fn main() {
|
||||
.cloned()
|
||||
.collect();
|
||||
}
|
||||
|
||||
// Issue #6808
|
||||
let arr: [u8; 64] = [0; 64];
|
||||
let _: Vec<_> = arr.iter().cloned().collect();
|
||||
}
|
||||
|
@ -22,5 +22,11 @@ LL | | .cloned()
|
||||
LL | | .collect();
|
||||
| |______________________^ help: try: `.to_vec()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
|
||||
--> $DIR/iter_cloned_collect.rs:28:24
|
||||
|
|
||||
LL | let _: Vec<_> = arr.iter().cloned().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -151,4 +151,16 @@ const fn const_fn_result_unwrap_or() {
|
||||
};
|
||||
}
|
||||
|
||||
mod issue6965 {
|
||||
macro_rules! some_macro {
|
||||
() => {
|
||||
if 1 > 2 { Some(1) } else { None }
|
||||
};
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let _ = some_macro!().unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -190,4 +190,19 @@ const fn const_fn_result_unwrap_or() {
|
||||
};
|
||||
}
|
||||
|
||||
mod issue6965 {
|
||||
macro_rules! some_macro {
|
||||
() => {
|
||||
if 1 > 2 { Some(1) } else { None }
|
||||
};
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let _ = match some_macro!() {
|
||||
Some(val) => val,
|
||||
None => 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -141,5 +141,15 @@ LL | | Err(_) => "Alice",
|
||||
LL | | };
|
||||
| |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: this pattern reimplements `Option::unwrap_or`
|
||||
--> $DIR/manual_unwrap_or.rs:201:17
|
||||
|
|
||||
LL | let _ = match some_macro!() {
|
||||
| _________________^
|
||||
LL | | Some(val) => val,
|
||||
LL | | None => 0,
|
||||
LL | | };
|
||||
| |_________^ help: replace with: `some_macro!().unwrap_or(0)`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
use std::ops::{Deref, RangeFrom};
|
||||
|
||||
fn cloned_instead_of_copied() {
|
||||
let _ = [1].iter().cloned();
|
||||
}
|
||||
|
||||
fn option_as_ref_deref() {
|
||||
let mut opt = Some(String::from("123"));
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: stripping a prefix manually
|
||||
--> $DIR/min_rust_version_attr.rs:156:24
|
||||
--> $DIR/min_rust_version_attr.rs:160:24
|
||||
|
|
||||
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::manual-strip` implied by `-D warnings`
|
||||
note: the prefix was tested here
|
||||
--> $DIR/min_rust_version_attr.rs:155:9
|
||||
--> $DIR/min_rust_version_attr.rs:159:9
|
||||
|
|
||||
LL | if s.starts_with("hello, ") {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -17,13 +17,13 @@ LL | assert_eq!(<stripped>.to_uppercase(), "WORLD!");
|
||||
|
|
||||
|
||||
error: stripping a prefix manually
|
||||
--> $DIR/min_rust_version_attr.rs:168:24
|
||||
--> $DIR/min_rust_version_attr.rs:172:24
|
||||
|
|
||||
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the prefix was tested here
|
||||
--> $DIR/min_rust_version_attr.rs:167:9
|
||||
--> $DIR/min_rust_version_attr.rs:171:9
|
||||
|
|
||||
LL | if s.starts_with("hello, ") {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -96,78 +96,6 @@ where
|
||||
|
||||
fn main() {}
|
||||
|
||||
mod question_mark_none {
|
||||
#![clippy::msrv = "1.12.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
Some(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
Ok(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
mod question_mark_result {
|
||||
#![clippy::msrv = "1.21.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
Some(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
to.magic // should be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
mod question_mark_both {
|
||||
#![clippy::msrv = "1.22.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
to.magic // should be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
to.magic // should be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
// #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use,
|
||||
// the suggestion fails to apply; do not lint
|
||||
macro_rules! some_in_macro {
|
||||
|
@ -96,78 +96,6 @@ where
|
||||
|
||||
fn main() {}
|
||||
|
||||
mod question_mark_none {
|
||||
#![clippy::msrv = "1.12.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
Some(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
Ok(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
mod question_mark_result {
|
||||
#![clippy::msrv = "1.21.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
Some(to.magic?) // should not be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
Ok(to.magic?) // should be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
mod question_mark_both {
|
||||
#![clippy::msrv = "1.22.0"]
|
||||
fn needless_question_mark_option() -> Option<usize> {
|
||||
struct TO {
|
||||
magic: Option<usize>,
|
||||
}
|
||||
let to = TO { magic: None };
|
||||
Some(to.magic?) // should be triggered
|
||||
}
|
||||
|
||||
fn needless_question_mark_result() -> Result<usize, bool> {
|
||||
struct TO {
|
||||
magic: Result<usize, bool>,
|
||||
}
|
||||
let to = TO { magic: Ok(1_usize) };
|
||||
Ok(to.magic?) // should be triggered
|
||||
}
|
||||
|
||||
fn main() {
|
||||
needless_question_mark_option();
|
||||
needless_question_mark_result();
|
||||
}
|
||||
}
|
||||
|
||||
// #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use,
|
||||
// the suggestion fails to apply; do not lint
|
||||
macro_rules! some_in_macro {
|
||||
|
@ -67,25 +67,7 @@ LL | return Ok(t.magic?);
|
||||
| ^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:138:9
|
||||
|
|
||||
LL | Ok(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:154:9
|
||||
|
|
||||
LL | Some(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:162:9
|
||||
|
|
||||
LL | Ok(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:187:27
|
||||
--> $DIR/needless_question_mark.rs:115:27
|
||||
|
|
||||
LL | || -> Option<_> { Some(Some($expr)?) }()
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)`
|
||||
@ -95,5 +77,5 @@ LL | let _x = some_and_qmark_in_macro!(x?);
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
#![warn(clippy::single_component_path_imports)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
// #7106: use statements exporting a macro within a crate should not trigger lint
|
||||
|
||||
macro_rules! m1 {
|
||||
() => {};
|
||||
}
|
||||
pub(crate) use m1; // ok
|
||||
|
||||
macro_rules! m2 {
|
||||
() => {};
|
||||
}
|
||||
// fail
|
||||
|
||||
fn main() {
|
||||
m1!();
|
||||
m2!();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
#![warn(clippy::single_component_path_imports)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
// #7106: use statements exporting a macro within a crate should not trigger lint
|
||||
|
||||
macro_rules! m1 {
|
||||
() => {};
|
||||
}
|
||||
pub(crate) use m1; // ok
|
||||
|
||||
macro_rules! m2 {
|
||||
() => {};
|
||||
}
|
||||
use m2; // fail
|
||||
|
||||
fn main() {
|
||||
m1!();
|
||||
m2!();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
error: this import is redundant
|
||||
--> $DIR/single_component_path_imports_macro.rs:16:1
|
||||
|
|
||||
LL | use m2; // fail
|
||||
| ^^^^^^^ help: remove it entirely
|
||||
|
|
||||
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -8,4 +8,9 @@ fn main() {
|
||||
let item = &item1;
|
||||
println!("{}", item);
|
||||
}
|
||||
|
||||
{
|
||||
let item = &item1;
|
||||
println!("{:?}", item);
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,8 @@ fn main() {
|
||||
for item in &[item1] {
|
||||
println!("{}", item);
|
||||
}
|
||||
|
||||
for item in [item1].iter() {
|
||||
println!("{:?}", item);
|
||||
}
|
||||
}
|
||||
|
@ -15,5 +15,21 @@ LL | println!("{}", item);
|
||||
LL | }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
error: for loop over a single element
|
||||
--> $DIR/single_element_loop.rs:11:5
|
||||
|
|
||||
LL | / for item in [item1].iter() {
|
||||
LL | | println!("{:?}", item);
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL | {
|
||||
LL | let item = &item1;
|
||||
LL | println!("{:?}", item);
|
||||
LL | }
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![allow(dead_code)]
|
||||
#![warn(clippy::unused_io_amount)]
|
||||
|
||||
use std::io;
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn question_mark<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
|
||||
s.write(b"test")?;
|
||||
@ -22,4 +22,43 @@ fn vectored<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ok(file: &str) -> Option<()> {
|
||||
let mut reader = std::fs::File::open(file).ok()?;
|
||||
let mut result = [0u8; 0];
|
||||
reader.read(&mut result).ok()?;
|
||||
Some(())
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_closure)]
|
||||
#[allow(clippy::bind_instead_of_map)]
|
||||
fn or_else(file: &str) -> io::Result<()> {
|
||||
let mut reader = std::fs::File::open(file)?;
|
||||
let mut result = [0u8; 0];
|
||||
reader.read(&mut result).or_else(|err| Err(err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
Kind,
|
||||
}
|
||||
|
||||
fn or(file: &str) -> Result<(), Error> {
|
||||
let mut reader = std::fs::File::open(file).unwrap();
|
||||
let mut result = [0u8; 0];
|
||||
reader.read(&mut result).or(Err(Error::Kind))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn combine_or(file: &str) -> Result<(), Error> {
|
||||
let mut reader = std::fs::File::open(file).unwrap();
|
||||
let mut result = [0u8; 0];
|
||||
reader
|
||||
.read(&mut result)
|
||||
.or(Err(Error::Kind))
|
||||
.or(Err(Error::Kind))
|
||||
.expect("error");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -36,5 +36,33 @@ error: written amount is not handled
|
||||
LL | s.write_vectored(&[io::IoSlice::new(&[])])?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: read amount is not handled. Use `Read::read_exact` instead
|
||||
--> $DIR/unused_io_amount.rs:28:5
|
||||
|
|
||||
LL | reader.read(&mut result).ok()?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: read amount is not handled. Use `Read::read_exact` instead
|
||||
--> $DIR/unused_io_amount.rs:37:5
|
||||
|
|
||||
LL | reader.read(&mut result).or_else(|err| Err(err))?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: read amount is not handled. Use `Read::read_exact` instead
|
||||
--> $DIR/unused_io_amount.rs:49:5
|
||||
|
|
||||
LL | reader.read(&mut result).or(Err(Error::Kind))?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: read amount is not handled. Use `Read::read_exact` instead
|
||||
--> $DIR/unused_io_amount.rs:56:5
|
||||
|
|
||||
LL | / reader
|
||||
LL | | .read(&mut result)
|
||||
LL | | .or(Err(Error::Kind))
|
||||
LL | | .or(Err(Error::Kind))
|
||||
LL | | .expect("error");
|
||||
| |________________________^
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
@ -975,7 +975,7 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
|
||||
}
|
||||
} else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
|
||||
if let Some(idx) = lldb_ver.find(not_a_digit) {
|
||||
let version: u32 = lldb_ver[..idx].parse().unwrap();
|
||||
let version: u32 = lldb_ver[..idx].parse().ok()?;
|
||||
return Some((version * 100, full_version_line.contains("rust-enabled")));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user