separate the receiver from arguments in HIR under /clippy

This commit is contained in:
Takayuki Maeda 2022-09-01 18:43:35 +09:00
parent 9ae329232b
commit 4bcaddeeb2
111 changed files with 662 additions and 558 deletions

View file

@ -118,9 +118,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
ExprKind::Call(first, [.., last])
| ExprKind::MethodCall(_, [first, .., last], _)
| ExprKind::MethodCall(_, first, [.., last], _)
| ExprKind::Binary(_, first, last)
| ExprKind::Tup([first, .., last])
| ExprKind::Assign(first, last, _)

View file

@ -155,13 +155,7 @@ where
});
}
pub fn span_lint_hir(
cx: &LateContext<'_>,
lint: &'static Lint,
hir_id: HirId,
sp: Span,
msg: &str,
) {
pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
let mut diag = diag.build(msg);
docs_link(&mut diag, lint);

View file

@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion {
}
/// Determine the eagerness of the given function call.
fn fn_eagerness<'tcx>(
cx: &LateContext<'tcx>,
fn_id: DefId,
name: Symbol,
args: &'tcx [Expr<'_>],
) -> EagernessSuggestion {
fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
use EagernessSuggestion::{Eager, Lazy, NoChange};
let name = name.as_str();
@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>(
None => return Lazy,
};
if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
if matches!(
cx.tcx.crate_name(fn_id.krate),
sym::std | sym::core | sym::alloc | sym::proc_macro
@ -127,10 +122,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
},
Res::Def(_, id) => match path {
QPath::Resolved(_, p) => {
self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
self.eagerness |=
fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty());
},
QPath::TypeRelative(_, name) => {
self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
},
QPath::LangItem(..) => self.eagerness = Lazy,
},
@ -141,12 +137,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
self.eagerness |= NoChange;
return;
},
ExprKind::MethodCall(name, args, _) => {
ExprKind::MethodCall(name, ..) => {
self.eagerness |= self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
.map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
.map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
},
ExprKind::Index(_, e) => {
let ty = self.cx.typeck_results().expr_ty_adjusted(e);

View file

@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> {
&& self.eq_expr(l.body, r.body)
})
},
(&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => {
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
(
&ExprKind::MethodCall(l_path, l_receiver, l_args, _),
&ExprKind::MethodCall(r_path, r_receiver, r_args, _),
) => {
self.inner.allow_side_effects
&& self.eq_path_segment(l_path, r_path)
&& self.eq_expr(l_receiver, r_receiver)
&& self.eq_exprs(l_args, r_args)
},
(&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
self.eq_expr(le, re) && self.eq_array_length(ll, rl)
@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
s.hash(&mut self.s);
},
ExprKind::MethodCall(path, args, ref _fn_span) => {
ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
self.hash_name(path.ident.name);
self.hash_expr(receiver);
self.hash_exprs(args);
},
ExprKind::ConstBlock(ref l_id) => {

View file

@ -1036,21 +1036,21 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
pub fn method_calls<'tcx>(
expr: &'tcx Expr<'tcx>,
max_depth: usize,
) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
) -> (Vec<Symbol>, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec<Span>) {
let mut method_names = Vec::with_capacity(max_depth);
let mut arg_lists = Vec::with_capacity(max_depth);
let mut spans = Vec::with_capacity(max_depth);
let mut current = expr;
for _ in 0..max_depth {
if let ExprKind::MethodCall(path, args, _) = &current.kind {
if args.iter().any(|e| e.span.from_expansion()) {
if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
break;
}
method_names.push(path.ident.name);
arg_lists.push(&**args);
arg_lists.push((*receiver, &**args));
spans.push(path.ident.span);
current = &args[0];
current = receiver;
} else {
break;
}
@ -1065,18 +1065,18 @@ pub fn method_calls<'tcx>(
/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
/// containing the `Expr`s for
/// `.bar()` and `.baz()`
pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
let mut current = expr;
let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() {
// method chains are stored last -> first
if let ExprKind::MethodCall(path, args, _) = current.kind {
if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
if args.iter().any(|e| e.span.from_expansion()) {
if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
return None;
}
matched.push(args); // build up `matched` backwards
current = &args[0]; // go to parent expression
matched.push((receiver, args)); // build up `matched` backwards
current = receiver; // go to parent expression
} else {
return None;
}
@ -1239,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
})
},
ExprKind::MethodCall(_, args, _) => {
let i = args.iter().position(|arg| arg.hir_id == id)?;
ExprKind::MethodCall(_, receiver, args, _) => {
let i = std::iter::once(receiver)
.chain(args.iter())
.position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())

View file

@ -36,7 +36,7 @@ fn extract_clone_suggestions<'tcx>(
if abort {
return false;
}
if let ExprKind::MethodCall(seg, [recv], _) = expr.kind {
if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind {
if path_to_local_id(recv, id) {
if seg.ident.name.as_str() == "capacity" {
abort = true;

View file

@ -373,12 +373,14 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
| AssocOp::LessEqual
| AssocOp::NotEqual
| AssocOp::Greater
| AssocOp::GreaterEqual => format!(
"{} {} {}",
lhs,
op.to_ast_binop().expect("Those are AST ops").to_string(),
rhs
),
| AssocOp::GreaterEqual => {
format!(
"{} {} {}",
lhs,
op.to_ast_binop().expect("Those are AST ops").to_string(),
rhs
)
},
AssocOp::Assign => format!("{} = {}", lhs, rhs),
AssocOp::AssignOp(op) => {
format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
@ -868,15 +870,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
/// indicates whether the function from `parent_expr` takes its args by double reference
fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
let ty = match parent_expr.kind {
ExprKind::MethodCall(_, call_args, _) => {
ExprKind::MethodCall(_, receiver, call_args, _) => {
if let Some(sig) = self
.cx
.typeck_results()
.type_dependent_def_id(parent_expr.hir_id)
.map(|did| self.cx.tcx.fn_sig(did).skip_binder())
{
call_args
.iter()
std::iter::once(receiver)
.chain(call_args.iter())
.position(|arg| arg.hir_id == cmt_hir_id)
.map(|i| sig.inputs()[i])
} else {
@ -933,14 +935,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
match &parent_expr.kind {
// given expression is the self argument and will be handled completely by the compiler
// i.e.: `|x| x.is_something()`
ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj);
self.next_pos = span.hi();
return;
},
// item is used in a call
// i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => {
ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();

View file

@ -620,7 +620,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
helper(typeck, true, arg, f)?;
}
},
ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => {
ExprKind::MethodCall(_, receiver, args, _) => {
helper(typeck, true, receiver, f)?;
for arg in args {
helper(typeck, true, arg, f)?;
}
},
ExprKind::Tup(args) | ExprKind::Array(args) => {
for arg in args {
helper(typeck, true, arg, f)?;
}