mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-24 05:33:27 +00:00
Added inferred local type comparion to SpanlessEq
This commit is contained in:
parent
7e90bb671a
commit
2992b19c82
4 changed files with 65 additions and 5 deletions
|
@ -293,10 +293,11 @@ fn lint_same_then_else<'tcx>(
|
||||||
/// The return tuple is structured as follows:
|
/// The return tuple is structured as follows:
|
||||||
/// 1. The amount of equal statements from the start
|
/// 1. The amount of equal statements from the start
|
||||||
/// 2. The amount of equal statements from the end
|
/// 2. The amount of equal statements from the end
|
||||||
/// 3. An indication if the block expressions are the same. This will also be true if both are `None`
|
/// 3. An indication if the block expressions are the same. This will also be true if both are
|
||||||
|
/// `None`
|
||||||
///
|
///
|
||||||
/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `(0, 0, false)`
|
/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `(0, 0,
|
||||||
/// to aboard any further processing and avoid duplicate lint triggers.
|
/// false)` to aboard any further processing and avoid duplicate lint triggers.
|
||||||
fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize, usize, bool) {
|
fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize, usize, bool) {
|
||||||
let mut start_eq = usize::MAX;
|
let mut start_eq = usize::MAX;
|
||||||
let mut end_eq = usize::MAX;
|
let mut end_eq = usize::MAX;
|
||||||
|
@ -307,7 +308,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize,
|
||||||
|
|
||||||
// `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
|
// `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
|
||||||
// The comparison therefore needs to be done in a way that builds the correct context.
|
// The comparison therefore needs to be done in a way that builds the correct context.
|
||||||
let mut evaluator = SpanlessEq::new(cx);
|
let mut evaluator = SpanlessEq::new(cx).enable_check_inferred_local_types();
|
||||||
let mut evaluator = evaluator.inter_expr();
|
let mut evaluator = evaluator.inter_expr();
|
||||||
|
|
||||||
let current_start_eq = count_eq(&mut l_stmts.iter(), &mut r_stmts.iter(), |l, r| evaluator.eq_stmt(l, r));
|
let current_start_eq = count_eq(&mut l_stmts.iter(), &mut r_stmts.iter(), |l, r| evaluator.eq_stmt(l, r));
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::consts::{constant_context, constant_simple};
|
use crate::consts::{constant_context, constant_simple};
|
||||||
use crate::differing_macro_contexts;
|
use crate::differing_macro_contexts;
|
||||||
use crate::source::snippet_opt;
|
use crate::source::snippet_opt;
|
||||||
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::InlineAsmTemplatePiece;
|
use rustc_ast::ast::InlineAsmTemplatePiece;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
|
@ -29,6 +30,30 @@ pub struct SpanlessEq<'a, 'tcx> {
|
||||||
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
|
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
|
||||||
allow_side_effects: bool,
|
allow_side_effects: bool,
|
||||||
expr_fallback: Option<Box<dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
|
expr_fallback: Option<Box<dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
|
||||||
|
/// This adds an additional type comparison to locals that insures that even the
|
||||||
|
/// inferred of the value is the same.
|
||||||
|
///
|
||||||
|
/// **Example**
|
||||||
|
/// * Context 1
|
||||||
|
/// ```ignore
|
||||||
|
/// let vec = Vec::new();
|
||||||
|
/// vec.push("A string");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// * Context 2
|
||||||
|
/// ```ignore
|
||||||
|
/// let vec = Vec::new();
|
||||||
|
/// vec.push(0); // An integer
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Only comparing the first local definition would usually return that they are
|
||||||
|
/// equal, since they are identical. However, they are different due to the context
|
||||||
|
/// as they have different inferred types.
|
||||||
|
///
|
||||||
|
/// This option enables or disables the specific check of the inferred type.
|
||||||
|
///
|
||||||
|
/// Note: This check will only be done if `self.maybe_typeck_results` is `Some()`.
|
||||||
|
check_inferred_local_types: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
|
@ -38,6 +63,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
maybe_typeck_results: cx.maybe_typeck_results(),
|
maybe_typeck_results: cx.maybe_typeck_results(),
|
||||||
allow_side_effects: true,
|
allow_side_effects: true,
|
||||||
expr_fallback: None,
|
expr_fallback: None,
|
||||||
|
check_inferred_local_types: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +82,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_check_inferred_local_types(self) -> Self {
|
||||||
|
Self {
|
||||||
|
check_inferred_local_types: true,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use this method to wrap comparisons that may involve inter-expression context.
|
/// Use this method to wrap comparisons that may involve inter-expression context.
|
||||||
/// See `self.locals`.
|
/// See `self.locals`.
|
||||||
pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
|
pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
|
||||||
|
@ -96,6 +129,21 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
|
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
|
||||||
match (&left.kind, &right.kind) {
|
match (&left.kind, &right.kind) {
|
||||||
(&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
|
(&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
|
||||||
|
// See `SpanlessEq::check_inferred_local_types` for an explication of this check
|
||||||
|
if_chain! {
|
||||||
|
if l.ty.is_none() && r.ty.is_none();
|
||||||
|
if self.inner.check_inferred_local_types;
|
||||||
|
if let Some(tcx) = self.inner.maybe_typeck_results;
|
||||||
|
|
||||||
|
// Check the inferred types
|
||||||
|
let l_ty = tcx.pat_ty(&l.pat);
|
||||||
|
let r_ty = tcx.pat_ty(&r.pat);
|
||||||
|
if l_ty != r_ty;
|
||||||
|
then {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
|
// eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
|
||||||
// these only get added if the init and type is equal.
|
// these only get added if the init and type is equal.
|
||||||
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
|
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
|
||||||
|
|
|
@ -1212,7 +1212,7 @@ pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
|
||||||
let map = cx.tcx.hir();
|
let map = cx.tcx.hir();
|
||||||
let parent_id = map.get_parent_node(expr.hir_id);
|
let parent_id = map.get_parent_node(expr.hir_id);
|
||||||
let parent_node = map.get(parent_id);
|
let parent_node = map.get(parent_id);
|
||||||
|
|
||||||
// Check for `if`
|
// Check for `if`
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Node::Expr(expr) = parent_node;
|
if let Node::Expr(expr) = parent_node;
|
||||||
|
|
|
@ -100,4 +100,15 @@ fn check_if_same_than_else_mask() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::vec_init_then_push)]
|
||||||
|
fn pf_local_with_inferred_type_issue7053() {
|
||||||
|
if true {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.push(0);
|
||||||
|
} else {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.push("");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
Loading…
Reference in a new issue