Add support for using qualified paths with structs in expression and pattern

position.
This commit is contained in:
Ryan Levick 2020-12-10 13:20:07 +01:00 committed by Ryan Levick
parent 626dc5945b
commit 611b74e1fe
5 changed files with 25 additions and 14 deletions

View File

@ -5,7 +5,7 @@ use rustc_lint::{EarlyContext, LintContext};
use super::UNNEEDED_FIELD_PATTERN; use super::UNNEEDED_FIELD_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind { if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind {
let mut wilds = 0; let mut wilds = 0;
let type_name = npat let type_name = npat
.segments .segments

View File

@ -7,7 +7,7 @@ use rustc_span::source_map::Span;
use super::UNNEEDED_WILDCARD_PATTERN; use super::UNNEEDED_WILDCARD_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind { if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) { if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
if let Some((left_index, left_pat)) = patterns[..rest_index] if let Some((left_index, left_pat)) = patterns[..rest_index]
.iter() .iter()

View File

@ -139,7 +139,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
self.check_ident(ident); self.check_ident(ident);
} }
}, },
PatKind::Struct(_, ref fields, _) => { PatKind::Struct(_, _, ref fields, _) => {
for field in fields { for field in fields {
if !field.is_shorthand { if !field.is_shorthand {
self.visit_pat(&field.pat); self.visit_pat(&field.pat);

View File

@ -1,6 +1,6 @@
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)] #![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::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{meets_msrv, msrvs, over}; use clippy_utils::{meets_msrv, msrvs, over};
use rustc_ast::mut_visit::*; use rustc_ast::mut_visit::*;
@ -273,16 +273,16 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
|k| always_pat!(k, Tuple(ps) => ps), |k| always_pat!(k, Tuple(ps) => ps),
), ),
// Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`. // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
TupleStruct(path1, ps1) => extend_with_matching_product( TupleStruct(qself1, path1, ps1) => extend_with_matching_product(
ps1, start, alternatives, ps1, start, alternatives,
|k, ps1, idx| matches!( |k, ps1, idx| matches!(
k, k,
TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
), ),
|k| always_pat!(k, TupleStruct(_, ps) => ps), |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
), ),
// Transform a record pattern `S { fp_0, ..., fp_n }`. // Transform a record pattern `S { fp_0, ..., fp_n }`.
Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives), Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
}; };
alternatives[focus_idx].kind = focus_kind; alternatives[focus_idx].kind = focus_kind;
@ -294,6 +294,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
fn extend_with_struct_pat( fn extend_with_struct_pat(
qself1: &Option<ast::QSelf>,
path1: &ast::Path, path1: &ast::Path,
fps1: &mut Vec<ast::PatField>, fps1: &mut Vec<ast::PatField>,
rest1: bool, rest1: bool,
@ -306,8 +307,9 @@ fn extend_with_struct_pat(
start, start,
alternatives, alternatives,
|k| { |k| {
matches!(k, Struct(path2, fps2, rest2) matches!(k, Struct(qself2, path2, fps2, rest2)
if rest1 == *rest2 // If one struct pattern has `..` so must the other. if rest1 == *rest2 // If one struct pattern has `..` so must the other.
&& eq_maybe_qself(qself1, qself2)
&& eq_path(path1, path2) && eq_path(path1, path2)
&& fps1.len() == fps2.len() && fps1.len() == fps2.len()
&& fps1.iter().enumerate().all(|(idx_1, fp1)| { && fps1.iter().enumerate().all(|(idx_1, fp1)| {
@ -323,7 +325,7 @@ fn extend_with_struct_pat(
})) }))
}, },
// Extract `p2_k`. // Extract `p2_k`.
|k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat), |k| always_pat!(k, Struct(_, _, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
); );
extend_with_tail_or(&mut fps1[idx].pat, tail_or) extend_with_tail_or(&mut fps1[idx].pat, tail_or)
}) })

View File

@ -47,9 +47,9 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
(TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
(Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => { (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
}, },
(Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
@ -78,6 +78,14 @@ pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
l.position == r.position && eq_ty(&l.ty, &r.ty) l.position == r.position && eq_ty(&l.ty, &r.ty)
} }
pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
match (l, r) {
(Some(l), Some(r)) => eq_qself(l, r),
(None, None) => true,
_ => false
}
}
pub fn eq_path(l: &Path, r: &Path) -> bool { pub fn eq_path(l: &Path, r: &Path) -> bool {
over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r)) over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
} }
@ -170,7 +178,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(Struct(lse), Struct(rse)) => { (Struct(lse), Struct(rse)) => {
eq_path(&lse.path, &rse.path) eq_maybe_qself(&lse.qself, &rse.qself)
&& eq_path(&lse.path, &rse.path)
&& eq_struct_rest(&lse.rest, &rse.rest) && eq_struct_rest(&lse.rest, &rse.rest)
&& unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r)) && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
}, },