Handle or patterns in single_match
and single_match_else
This commit is contained in:
parent
514824ff9d
commit
8bcecfff95
@ -180,9 +180,8 @@ enum CommonPrefixSearcher<'a> {
|
||||
}
|
||||
impl<'a> CommonPrefixSearcher<'a> {
|
||||
fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
|
||||
match path {
|
||||
[path @ .., _] => self.with_prefix(path),
|
||||
[] => (),
|
||||
if let [path @ .., _] = path {
|
||||
self.with_prefix(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,19 +33,17 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||
.filter_map(|arm| {
|
||||
if let Arm { pat, guard: None, .. } = *arm {
|
||||
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||
let lhs_const = match lhs {
|
||||
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
||||
None => {
|
||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||
mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
|
||||
},
|
||||
let lhs_const = if let Some(lhs) = lhs {
|
||||
constant(cx, cx.typeck_results(), lhs)?
|
||||
} else {
|
||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||
mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
|
||||
};
|
||||
let rhs_const = match rhs {
|
||||
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
||||
None => {
|
||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||
mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
|
||||
},
|
||||
let rhs_const = if let Some(rhs) = rhs {
|
||||
constant(cx, cx.typeck_results(), rhs)?
|
||||
} else {
|
||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||
mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
|
||||
};
|
||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||
let rhs_val = rhs_const.int_value(cx, ty)?;
|
||||
|
@ -1,14 +1,17 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{
|
||||
is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
|
||||
is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
|
||||
};
|
||||
use core::cmp::max;
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, BindingMode, Expr, ExprKind, Pat, PatKind};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_pat, Visitor};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef};
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
|
||||
@ -29,7 +32,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
||||
pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], expr: &'tcx Expr<'_>) {
|
||||
if let [arm1, arm2] = arms
|
||||
&& arm1.guard.is_none()
|
||||
&& arm2.guard.is_none()
|
||||
@ -52,10 +55,29 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
||||
return;
|
||||
};
|
||||
|
||||
let ty = cx.typeck_results().expr_ty(ex);
|
||||
if (*ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id))
|
||||
&& (is_wild(arm2.pat) || form_exhaustive_matches(cx, ty, arm1.pat, arm2.pat))
|
||||
{
|
||||
let typeck = cx.typeck_results();
|
||||
if *typeck.expr_ty(ex).peel_refs().kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
|
||||
let mut v = PatVisitor {
|
||||
typeck,
|
||||
has_enum: false,
|
||||
};
|
||||
if v.visit_pat(arm2.pat).is_break() {
|
||||
return;
|
||||
}
|
||||
if v.has_enum {
|
||||
let cx = PatCtxt {
|
||||
tcx: cx.tcx,
|
||||
param_env: cx.param_env,
|
||||
typeck,
|
||||
arena: DroplessArena::default(),
|
||||
};
|
||||
let mut state = PatState::Other;
|
||||
if !(state.add_pat(&cx, arm2.pat) || state.add_pat(&cx, arm1.pat)) {
|
||||
// Don't lint if the pattern contains an enum which doesn't have a wild match.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
report_single_pattern(cx, ex, arm1, expr, els);
|
||||
}
|
||||
}
|
||||
@ -121,100 +143,227 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
|
||||
span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
|
||||
}
|
||||
|
||||
/// Returns `true` if all of the types in the pattern are enums which we know
|
||||
/// won't be expanded in the future
|
||||
fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> bool {
|
||||
let mut paths_and_types = Vec::new();
|
||||
collect_pat_paths(&mut paths_and_types, cx, pat, ty);
|
||||
paths_and_types.iter().all(|ty| in_candidate_enum(cx, *ty))
|
||||
struct PatVisitor<'tcx> {
|
||||
typeck: &'tcx TypeckResults<'tcx>,
|
||||
has_enum: bool,
|
||||
}
|
||||
|
||||
/// Returns `true` if the given type is an enum we know won't be expanded in the future
|
||||
fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
// list of candidate `Enum`s we know will never get any more members
|
||||
let candidates = [sym::Cow, sym::Option, sym::Result];
|
||||
|
||||
for candidate_ty in candidates {
|
||||
if is_type_diagnostic_item(cx, ty, candidate_ty) {
|
||||
return true;
|
||||
impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_pat(&mut self, pat: &'tcx Pat<'_>) -> Self::Result {
|
||||
if matches!(pat.kind, PatKind::Binding(..)) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum);
|
||||
walk_pat(self, pat)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Collects types from the given pattern
|
||||
fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) {
|
||||
match pat.kind {
|
||||
PatKind::Tuple(inner, _) => inner.iter().for_each(|p| {
|
||||
let p_ty = cx.typeck_results().pat_ty(p);
|
||||
collect_pat_paths(acc, cx, p, p_ty);
|
||||
}),
|
||||
PatKind::TupleStruct(..) | PatKind::Binding(BindingMode::NONE, .., None) | PatKind::Path(_) => {
|
||||
acc.push(ty);
|
||||
},
|
||||
_ => {},
|
||||
/// The context needed to manipulate a `PatState`.
|
||||
struct PatCtxt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
typeck: &'tcx TypeckResults<'tcx>,
|
||||
arena: DroplessArena,
|
||||
}
|
||||
|
||||
/// State for tracking whether a match can become non-exhaustive by adding a variant to a contained
|
||||
/// enum.
|
||||
///
|
||||
/// This treats certain std enums as if they will never be extended.
|
||||
enum PatState<'a> {
|
||||
/// Either a wild match or an uninteresting type. Uninteresting types include:
|
||||
/// * builtin types (e.g. `i32` or `!`)
|
||||
/// * A struct/tuple/array containing only uninteresting types.
|
||||
/// * A std enum containing only uninteresting types.
|
||||
Wild,
|
||||
/// A std enum we know won't be extended. Tracks the states of each variant separately.
|
||||
///
|
||||
/// This is not used for `Option` since it uses the current pattern to track it's state.
|
||||
StdEnum(&'a mut [PatState<'a>]),
|
||||
/// Either the initial state for a pattern or a non-std enum. There is currently no need to
|
||||
/// distinguish these cases.
|
||||
///
|
||||
/// For non-std enums there's no need to track the state of sub-patterns as the state of just
|
||||
/// this pattern on it's own is enough for linting. Consider two cases:
|
||||
/// * This enum has no wild match. This case alone is enough to determine we can lint.
|
||||
/// * This enum has a wild match and therefore all sub-patterns also have a wild match.
|
||||
///
|
||||
/// In both cases the sub patterns are not needed to determine whether to lint.
|
||||
Other,
|
||||
}
|
||||
impl<'a> PatState<'a> {
|
||||
/// Adds a set of patterns as a product type to the current state. Returns whether or not the
|
||||
/// current state is a wild match after the merge.
|
||||
fn add_product_pat<'tcx>(
|
||||
&mut self,
|
||||
cx: &'a PatCtxt<'tcx>,
|
||||
pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
|
||||
) -> bool {
|
||||
// Ideally this would actually keep track of the state separately for each pattern. Doing so would
|
||||
// require implementing something similar to exhaustiveness checking which is a significant increase
|
||||
// in complexity.
|
||||
//
|
||||
// For now treat this as a wild match only if all the sub-patterns are wild
|
||||
let is_wild = pats.into_iter().all(|p| {
|
||||
let mut state = Self::Other;
|
||||
state.add_pat(cx, p)
|
||||
});
|
||||
if is_wild {
|
||||
*self = Self::Wild;
|
||||
}
|
||||
is_wild
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the given arm of pattern matching contains wildcard patterns.
|
||||
fn contains_only_wilds(pat: &Pat<'_>) -> bool {
|
||||
match pat.kind {
|
||||
PatKind::Wild => true,
|
||||
PatKind::Tuple(inner, _) | PatKind::TupleStruct(_, inner, ..) => inner.iter().all(contains_only_wilds),
|
||||
_ => false,
|
||||
/// Attempts to get the state for the enum variant, initializing the current state if necessary.
|
||||
fn get_std_enum_variant<'tcx>(
|
||||
&mut self,
|
||||
cx: &'a PatCtxt<'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
path: &'tcx QPath<'_>,
|
||||
hir_id: HirId,
|
||||
) -> Option<(&mut Self, &'tcx VariantDef)> {
|
||||
let states = match self {
|
||||
Self::Wild => return None,
|
||||
Self::Other => {
|
||||
*self = Self::StdEnum(cx.arena.alloc_from_iter((0..adt.variants().len()).map(|_| Self::Other)));
|
||||
let Self::StdEnum(x) = self else {
|
||||
unreachable!();
|
||||
};
|
||||
x
|
||||
},
|
||||
Self::StdEnum(x) => x,
|
||||
};
|
||||
let i = match cx.typeck.qpath_res(path, hir_id) {
|
||||
Res::Def(DefKind::Ctor(..), id) => adt.variant_index_with_ctor_id(id),
|
||||
Res::Def(DefKind::Variant, id) => adt.variant_index_with_id(id),
|
||||
_ => return None,
|
||||
};
|
||||
Some((&mut states[i.as_usize()], adt.variant(i)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
|
||||
/// patterns without a wildcard.
|
||||
fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||
match (&left.kind, &right.kind) {
|
||||
(PatKind::Wild, _) | (_, PatKind::Wild) => true,
|
||||
(PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
|
||||
// We don't actually know the position and the presence of the `..` (dotdot) operator
|
||||
// in the arms, so we need to evaluate the correct offsets here in order to iterate in
|
||||
// both arms at the same time.
|
||||
let left_pos = left_pos.as_opt_usize();
|
||||
let right_pos = right_pos.as_opt_usize();
|
||||
let len = max(
|
||||
left_in.len() + usize::from(left_pos.is_some()),
|
||||
right_in.len() + usize::from(right_pos.is_some()),
|
||||
);
|
||||
let mut left_pos = left_pos.unwrap_or(usize::MAX);
|
||||
let mut right_pos = right_pos.unwrap_or(usize::MAX);
|
||||
let mut left_dot_space = 0;
|
||||
let mut right_dot_space = 0;
|
||||
for i in 0..len {
|
||||
let mut found_dotdot = false;
|
||||
if i == left_pos {
|
||||
left_dot_space += 1;
|
||||
if left_dot_space < len - left_in.len() {
|
||||
left_pos += 1;
|
||||
}
|
||||
found_dotdot = true;
|
||||
}
|
||||
if i == right_pos {
|
||||
right_dot_space += 1;
|
||||
if right_dot_space < len - right_in.len() {
|
||||
right_pos += 1;
|
||||
}
|
||||
found_dotdot = true;
|
||||
}
|
||||
if found_dotdot {
|
||||
continue;
|
||||
}
|
||||
if !contains_only_wilds(&left_in[i - left_dot_space])
|
||||
&& !contains_only_wilds(&right_in[i - right_dot_space])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fn check_all_wild_enum(&mut self) -> bool {
|
||||
if let Self::StdEnum(states) = self
|
||||
&& states.iter().all(|s| matches!(s, Self::Wild))
|
||||
{
|
||||
*self = Self::Wild;
|
||||
true
|
||||
},
|
||||
(PatKind::TupleStruct(..), PatKind::Path(_)) => pat_in_candidate_enum(cx, ty, right),
|
||||
(PatKind::TupleStruct(..), PatKind::TupleStruct(_, inner, _)) => {
|
||||
pat_in_candidate_enum(cx, ty, right) && inner.iter().all(contains_only_wilds)
|
||||
},
|
||||
_ => false,
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::similar_names)]
|
||||
fn add_struct_pats<'tcx>(
|
||||
&mut self,
|
||||
cx: &'a PatCtxt<'tcx>,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
path: &'tcx QPath<'tcx>,
|
||||
single_pat: Option<&'tcx Pat<'tcx>>,
|
||||
pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
|
||||
) -> bool {
|
||||
let ty::Adt(adt, _) = *cx.typeck.pat_ty(pat).kind() else {
|
||||
// Should never happen
|
||||
*self = Self::Wild;
|
||||
return true;
|
||||
};
|
||||
if adt.is_struct() {
|
||||
return if let Some(pat) = single_pat
|
||||
&& adt.non_enum_variant().fields.len() == 1
|
||||
{
|
||||
self.add_pat(cx, pat)
|
||||
} else {
|
||||
self.add_product_pat(cx, pats)
|
||||
};
|
||||
}
|
||||
match cx.tcx.get_diagnostic_name(adt.did()) {
|
||||
Some(sym::Option) => {
|
||||
if let Some(pat) = single_pat {
|
||||
self.add_pat(cx, pat)
|
||||
} else {
|
||||
*self = Self::Wild;
|
||||
true
|
||||
}
|
||||
},
|
||||
Some(sym::Result | sym::Cow) => {
|
||||
let Some((state, variant)) = self.get_std_enum_variant(cx, adt, path, pat.hir_id) else {
|
||||
return matches!(self, Self::Wild);
|
||||
};
|
||||
let is_wild = if let Some(pat) = single_pat
|
||||
&& variant.fields.len() == 1
|
||||
{
|
||||
state.add_pat(cx, pat)
|
||||
} else {
|
||||
state.add_product_pat(cx, pats)
|
||||
};
|
||||
is_wild && self.check_all_wild_enum()
|
||||
},
|
||||
_ => matches!(self, Self::Wild),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the pattern into the current state. Returns whether or not the current state is a wild
|
||||
/// match after the merge.
|
||||
#[expect(clippy::similar_names)]
|
||||
fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
|
||||
match pat.kind {
|
||||
PatKind::Path(_)
|
||||
if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
|
||||
ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
|
||||
ty::Tuple(tys) => !tys.is_empty(),
|
||||
ty::Array(_, len) => len.try_eval_target_usize(cx.tcx, cx.param_env) != Some(1),
|
||||
ty::Slice(..) => true,
|
||||
_ => false,
|
||||
} =>
|
||||
{
|
||||
matches!(self, Self::Wild)
|
||||
},
|
||||
|
||||
// Patterns for things which can only contain a single sub-pattern.
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
|
||||
self.add_pat(cx, pat)
|
||||
},
|
||||
PatKind::Tuple([sub_pat], pos)
|
||||
if pos.as_opt_usize().is_none() || cx.typeck.pat_ty(pat).tuple_fields().len() == 1 =>
|
||||
{
|
||||
self.add_pat(cx, sub_pat)
|
||||
},
|
||||
PatKind::Slice([sub_pat], _, []) | PatKind::Slice([], _, [sub_pat])
|
||||
if let ty::Array(_, len) = *cx.typeck.pat_ty(pat).kind()
|
||||
&& len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(1) =>
|
||||
{
|
||||
self.add_pat(cx, sub_pat)
|
||||
},
|
||||
|
||||
PatKind::Or(pats) => pats.iter().any(|p| self.add_pat(cx, p)),
|
||||
PatKind::Tuple(pats, _) => self.add_product_pat(cx, pats),
|
||||
PatKind::Slice(head, _, tail) => self.add_product_pat(cx, head.iter().chain(tail)),
|
||||
|
||||
PatKind::TupleStruct(ref path, pats, _) => self.add_struct_pats(
|
||||
cx,
|
||||
pat,
|
||||
path,
|
||||
if let [pat] = pats { Some(pat) } else { None },
|
||||
pats.iter(),
|
||||
),
|
||||
PatKind::Struct(ref path, pats, _) => self.add_struct_pats(
|
||||
cx,
|
||||
pat,
|
||||
path,
|
||||
if let [pat] = pats { Some(pat.pat) } else { None },
|
||||
pats.iter().map(|p| p.pat),
|
||||
),
|
||||
|
||||
PatKind::Wild
|
||||
| PatKind::Binding(_, _, _, None)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Never
|
||||
| PatKind::Err(_) => {
|
||||
*self = PatState::Wild;
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
//@aux-build:../../ui/auxiliary/proc_macros.rs
|
||||
#![rustfmt::skip]
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::let_and_return)]
|
||||
#![allow(clippy::redundant_closure_call)]
|
||||
#![allow(clippy::no_effect)]
|
||||
#![allow(clippy::unnecessary_operation)]
|
||||
#![allow(clippy::never_loop)]
|
||||
#![allow(clippy::needless_if)]
|
||||
#![warn(clippy::excessive_nesting)]
|
||||
#![allow(clippy::collapsible_if, clippy::blocks_in_conditions)]
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::let_and_return,
|
||||
clippy::redundant_closure_call,
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::never_loop,
|
||||
clippy::needless_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::blocks_in_conditions,
|
||||
clippy::single_match,
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:21:25
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:25:25
|
||||
|
|
||||
LL | let w = { 3 };
|
||||
| ^^^^^
|
||||
@ -9,7 +9,7 @@ LL | let w = { 3 };
|
||||
= help: to override `-D warnings` add `#[allow(clippy::excessive_nesting)]`
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:67:17
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:71:17
|
||||
|
|
||||
LL | / impl C {
|
||||
LL | | pub fn c() {}
|
||||
@ -19,7 +19,7 @@ LL | | }
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:81:25
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:85:25
|
||||
|
|
||||
LL | let x = { 1 }; // not a warning, but cc is
|
||||
| ^^^^^
|
||||
@ -27,7 +27,7 @@ LL | let x = { 1 }; // not a warning, but cc is
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:98:17
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:102:17
|
||||
|
|
||||
LL | / pub mod e {
|
||||
LL | | pub mod f {}
|
||||
@ -37,7 +37,7 @@ LL | | } // not here
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:111:18
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:115:18
|
||||
|
|
||||
LL | a_but_not({{{{{{{{0}}}}}}}});
|
||||
| ^^^^^^^^^^^
|
||||
@ -45,7 +45,7 @@ LL | a_but_not({{{{{{{{0}}}}}}}});
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:112:12
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:116:12
|
||||
|
|
||||
LL | a.a({{{{{{{{{0}}}}}}}}});
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -53,7 +53,7 @@ LL | a.a({{{{{{{{{0}}}}}}}}});
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:113:12
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:117:12
|
||||
|
|
||||
LL | (0, {{{{{{{1}}}}}}});
|
||||
| ^^^^^^^^^
|
||||
@ -61,7 +61,7 @@ LL | (0, {{{{{{{1}}}}}}});
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:118:25
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:122:25
|
||||
|
|
||||
LL | if true {
|
||||
| _________________________^
|
||||
@ -74,7 +74,7 @@ LL | | }
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:130:29
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:134:29
|
||||
|
|
||||
LL | let z = (|| {
|
||||
| _____________________________^
|
||||
@ -86,7 +86,7 @@ LL | | })();
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:149:13
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:13
|
||||
|
|
||||
LL | y += {{{{{5}}}}};
|
||||
| ^^^^^
|
||||
@ -94,7 +94,7 @@ LL | y += {{{{{5}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:150:20
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:20
|
||||
|
|
||||
LL | let z = y + {{{{{{{{{5}}}}}}}}};
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -102,7 +102,7 @@ LL | let z = y + {{{{{{{{{5}}}}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:151:12
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:155:12
|
||||
|
|
||||
LL | [0, {{{{{{{{{{0}}}}}}}}}}];
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -110,7 +110,7 @@ LL | [0, {{{{{{{{{{0}}}}}}}}}}];
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:152:25
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:25
|
||||
|
|
||||
LL | let mut xx = [0; {{{{{{{{100}}}}}}}}];
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -118,7 +118,7 @@ LL | let mut xx = [0; {{{{{{{{100}}}}}}}}];
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:11
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:157:11
|
||||
|
|
||||
LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -126,7 +126,7 @@ LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:13
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:13
|
||||
|
|
||||
LL | &mut {{{{{{{{{{y}}}}}}}}}};
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -134,7 +134,7 @@ LL | &mut {{{{{{{{{{y}}}}}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:17
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:17
|
||||
|
|
||||
LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
|
||||
| ^^^^
|
||||
@ -142,7 +142,7 @@ LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:28
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:28
|
||||
|
|
||||
LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
|
||||
| ^^^^^^^^^^
|
||||
@ -150,7 +150,7 @@ LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:28
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:28
|
||||
|
|
||||
LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -158,7 +158,7 @@ LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:48
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:48
|
||||
|
|
||||
LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
|
||||
| ^^^^^^^^
|
||||
@ -166,7 +166,7 @@ LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:14
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:14
|
||||
|
|
||||
LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -174,7 +174,7 @@ LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:35
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:35
|
||||
|
|
||||
LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
|
||||
| ^^^^^^^^^^^^
|
||||
@ -182,7 +182,7 @@ LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:23
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:23
|
||||
|
|
||||
LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -190,7 +190,7 @@ LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:8
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
|
||||
|
|
||||
LL | {{{{1;}}}}..{{{{{{3}}}}}};
|
||||
| ^^^^
|
||||
@ -198,7 +198,7 @@ LL | {{{{1;}}}}..{{{{{{3}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:20
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:20
|
||||
|
|
||||
LL | {{{{1;}}}}..{{{{{{3}}}}}};
|
||||
| ^^^^^^^
|
||||
@ -206,7 +206,7 @@ LL | {{{{1;}}}}..{{{{{{3}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:8
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:8
|
||||
|
|
||||
LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
|
||||
| ^^^^
|
||||
@ -214,7 +214,7 @@ LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:21
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:21
|
||||
|
|
||||
LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -222,7 +222,7 @@ LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:10
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:10
|
||||
|
|
||||
LL | ..{{{{{{{5}}}}}}};
|
||||
| ^^^^^^^^^
|
||||
@ -230,7 +230,7 @@ LL | ..{{{{{{{5}}}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:167:11
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:11
|
||||
|
|
||||
LL | ..={{{{{3}}}}};
|
||||
| ^^^^^
|
||||
@ -238,7 +238,7 @@ LL | ..={{{{{3}}}}};
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:172:8
|
||||
|
|
||||
LL | {{{{{1;}}}}}..;
|
||||
| ^^^^^^
|
||||
@ -246,7 +246,7 @@ LL | {{{{{1;}}}}}..;
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:20
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
|
||||
|
|
||||
LL | loop { break {{{{1}}}} };
|
||||
| ^^^^^
|
||||
@ -254,7 +254,7 @@ LL | loop { break {{{{1}}}} };
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:13
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:13
|
||||
|
|
||||
LL | loop {{{{{{}}}}}}
|
||||
| ^^^^^^
|
||||
@ -262,7 +262,7 @@ LL | loop {{{{{{}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:173:14
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:177:14
|
||||
|
|
||||
LL | match {{{{{{true}}}}}} {
|
||||
| ^^^^^^^^^^
|
||||
@ -270,7 +270,7 @@ LL | match {{{{{{true}}}}}} {
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:178:20
|
||||
|
|
||||
LL | true => {{{{}}}},
|
||||
| ^^
|
||||
@ -278,7 +278,7 @@ LL | true => {{{{}}}},
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:21
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:21
|
||||
|
|
||||
LL | false => {{{{}}}},
|
||||
| ^^
|
||||
@ -286,7 +286,7 @@ LL | false => {{{{}}}},
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:181:17
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:185:17
|
||||
|
|
||||
LL | / {
|
||||
LL | | println!("warning! :)");
|
||||
@ -296,7 +296,7 @@ LL | | }
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:190:28
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:194:28
|
||||
|
|
||||
LL | async fn c() -> u32 {{{{{{{0}}}}}}}
|
||||
| ^^^^^^^^^
|
||||
@ -304,7 +304,7 @@ LL | async fn c() -> u32 {{{{{{{0}}}}}}}
|
||||
= help: try refactoring your code to minimize nesting
|
||||
|
||||
error: this block is too nested
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:196:8
|
||||
--> tests/ui-toml/excessive_nesting/excessive_nesting.rs:200:8
|
||||
|
|
||||
LL | {{{{b().await}}}};
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -2,7 +2,8 @@
|
||||
// panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())',
|
||||
// compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::single_match)]
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Foo(i32);
|
||||
const FOO_REF_REF: &&Foo = &&Foo(42);
|
||||
|
@ -1,7 +1,7 @@
|
||||
//@aux-build:proc_macros.rs
|
||||
#![warn(clippy::all)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
#![allow(clippy::uninlined_format_args, clippy::single_match)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
@ -1,7 +1,7 @@
|
||||
//@aux-build:proc_macros.rs
|
||||
#![warn(clippy::all)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
#![allow(clippy::uninlined_format_args, clippy::single_match)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
@ -253,3 +253,46 @@ mod issue8634 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn issue11365() {
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
use Foo::{A, B, C};
|
||||
|
||||
match Some(A) {
|
||||
Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
match Some(A) {
|
||||
Some(A | B) => println!(),
|
||||
Some { 0: C } | None => {},
|
||||
}
|
||||
|
||||
match [A, A] {
|
||||
[A, _] => println!(),
|
||||
[_, A | B | C] => {},
|
||||
}
|
||||
|
||||
match Ok::<_, u32>(Some(A)) {
|
||||
Ok(Some(A)) => println!(),
|
||||
Err(_) | Ok(None | Some(B | C)) => {},
|
||||
}
|
||||
|
||||
if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }
|
||||
|
||||
match &Some(A) {
|
||||
Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
match &Some(A) {
|
||||
&Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
if let Some(A | B) = &Some(A) { println!() }
|
||||
}
|
||||
|
@ -311,3 +311,52 @@ fn block_comment(x: Result<i32, SomeError>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn issue11365() {
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
use Foo::{A, B, C};
|
||||
|
||||
match Some(A) {
|
||||
Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
match Some(A) {
|
||||
Some(A | B) => println!(),
|
||||
Some { 0: C } | None => {},
|
||||
}
|
||||
|
||||
match [A, A] {
|
||||
[A, _] => println!(),
|
||||
[_, A | B | C] => {},
|
||||
}
|
||||
|
||||
match Ok::<_, u32>(Some(A)) {
|
||||
Ok(Some(A)) => println!(),
|
||||
Err(_) | Ok(None | Some(B | C)) => {},
|
||||
}
|
||||
|
||||
match Ok::<_, u32>(Some(A)) {
|
||||
Ok(Some(A)) => println!(),
|
||||
Err(_) | Ok(None | Some(_)) => {},
|
||||
}
|
||||
|
||||
match &Some(A) {
|
||||
Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
match &Some(A) {
|
||||
&Some(A | B | C) => println!(),
|
||||
None => {},
|
||||
}
|
||||
|
||||
match &Some(A) {
|
||||
Some(A | B) => println!(),
|
||||
None | Some(_) => {},
|
||||
}
|
||||
}
|
||||
|
@ -198,5 +198,23 @@ LL + }
|
||||
LL + }
|
||||
|
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> tests/ui/single_match.rs:343:5
|
||||
|
|
||||
LL | / match Ok::<_, u32>(Some(A)) {
|
||||
LL | | Ok(Some(A)) => println!(),
|
||||
LL | | Err(_) | Ok(None | Some(_)) => {},
|
||||
LL | | }
|
||||
| |_____^ help: try: `if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> tests/ui/single_match.rs:358:5
|
||||
|
|
||||
LL | / match &Some(A) {
|
||||
LL | | Some(A | B) => println!(),
|
||||
LL | | None | Some(_) => {},
|
||||
LL | | }
|
||||
| |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }`
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
//@aux-build:proc_macros.rs
|
||||
#![warn(clippy::unneeded_field_pattern)]
|
||||
#![allow(dead_code, unused)]
|
||||
#![allow(dead_code, unused, clippy::single_match)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
Loading…
Reference in New Issue
Block a user