mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #101261 - TaKO8Ki:separate-receiver-from-arguments-in-hir, r=cjgillot
Separate the receiver from arguments in HIR Related to #100232 cc `@cjgillot`
This commit is contained in:
commit
b44197abb0
@ -68,10 +68,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
ParenthesizedGenericArgs::Err,
|
ParenthesizedGenericArgs::Err,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||||
));
|
));
|
||||||
let args = self.arena.alloc_from_iter(
|
let receiver = self.lower_expr(receiver);
|
||||||
[&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
|
let args =
|
||||||
);
|
self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
|
||||||
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
|
hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
|
||||||
}
|
}
|
||||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||||
let binop = self.lower_binop(binop);
|
let binop = self.lower_binop(binop);
|
||||||
|
@ -711,8 +711,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
self.suggested = true;
|
self.suggested = true;
|
||||||
} else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind
|
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
|
||||||
&& let hir::ExprKind::Index(val, index) = args[0].kind
|
&& let hir::ExprKind::Index(val, index) = receiver.kind
|
||||||
&& expr.span == self.assign_span
|
&& expr.span == self.assign_span
|
||||||
{
|
{
|
||||||
// val[index].path(args..);
|
// val[index].path(args..);
|
||||||
@ -724,7 +724,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
".get_mut(".to_string(),
|
".get_mut(".to_string(),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
index.span.shrink_to_hi().with_hi(args[0].span.hi()),
|
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
|
||||||
").map(|val| val".to_string(),
|
").map(|val| val".to_string(),
|
||||||
),
|
),
|
||||||
(sp.shrink_to_hi(), ")".to_string()),
|
(sp.shrink_to_hi(), ")".to_string()),
|
||||||
@ -911,11 +911,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
[
|
[
|
||||||
Expr {
|
Expr {
|
||||||
kind:
|
kind:
|
||||||
MethodCall(
|
MethodCall(path_segment, _, _, span),
|
||||||
path_segment,
|
|
||||||
_args,
|
|
||||||
span,
|
|
||||||
),
|
|
||||||
hir_id,
|
hir_id,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
|
@ -900,14 +900,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
let mut closure_span = None::<rustc_span::Span>;
|
let mut closure_span = None::<rustc_span::Span>;
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
hir::ExprKind::MethodCall(.., args, _) => {
|
hir::ExprKind::MethodCall(.., args, _) => {
|
||||||
// only the first closre parameter of the method. args[0] is MethodCall PathSegment
|
for arg in args {
|
||||||
for i in 1..args.len() {
|
|
||||||
if let hir::ExprKind::Closure(hir::Closure {
|
if let hir::ExprKind::Closure(hir::Closure {
|
||||||
capture_clause: hir::CaptureBy::Ref,
|
capture_clause: hir::CaptureBy::Ref,
|
||||||
..
|
..
|
||||||
}) = args[i].kind
|
}) = arg.kind
|
||||||
{
|
{
|
||||||
closure_span = Some(args[i].span.shrink_to_lo());
|
closure_span = Some(arg.span.shrink_to_lo());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1876,11 +1876,11 @@ pub enum ExprKind<'hir> {
|
|||||||
///
|
///
|
||||||
/// The `PathSegment` represents the method name and its generic arguments
|
/// The `PathSegment` represents the method name and its generic arguments
|
||||||
/// (within the angle brackets).
|
/// (within the angle brackets).
|
||||||
/// The first element of the `&[Expr]` is the expression that evaluates
|
/// The `&Expr` is the expression that evaluates
|
||||||
/// to the object on which the method is being called on (the receiver),
|
/// to the object on which the method is being called on (the receiver),
|
||||||
/// and the remaining elements are the rest of the arguments.
|
/// and the `&[Expr]` is the rest of the arguments.
|
||||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`.
|
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`.
|
||||||
/// The final `Span` represents the span of the function and arguments
|
/// The final `Span` represents the span of the function and arguments
|
||||||
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
|
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
|
||||||
///
|
///
|
||||||
@ -1888,7 +1888,7 @@ pub enum ExprKind<'hir> {
|
|||||||
/// the `hir_id` of the `MethodCall` node itself.
|
/// the `hir_id` of the `MethodCall` node itself.
|
||||||
///
|
///
|
||||||
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
|
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
|
||||||
MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
|
MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
|
||||||
/// A tuple (e.g., `(a, b, c, d)`).
|
/// A tuple (e.g., `(a, b, c, d)`).
|
||||||
Tup(&'hir [Expr<'hir>]),
|
Tup(&'hir [Expr<'hir>]),
|
||||||
/// A binary operation (e.g., `a + b`, `a * b`).
|
/// A binary operation (e.g., `a + b`, `a * b`).
|
||||||
@ -3492,8 +3492,8 @@ mod size_asserts {
|
|||||||
// These are in alphabetical order, which is easy to maintain.
|
// These are in alphabetical order, which is easy to maintain.
|
||||||
static_assert_size!(Block<'_>, 48);
|
static_assert_size!(Block<'_>, 48);
|
||||||
static_assert_size!(Body<'_>, 32);
|
static_assert_size!(Body<'_>, 32);
|
||||||
static_assert_size!(Expr<'_>, 56);
|
static_assert_size!(Expr<'_>, 64);
|
||||||
static_assert_size!(ExprKind<'_>, 40);
|
static_assert_size!(ExprKind<'_>, 48);
|
||||||
static_assert_size!(FnDecl<'_>, 40);
|
static_assert_size!(FnDecl<'_>, 40);
|
||||||
static_assert_size!(ForeignItem<'_>, 72);
|
static_assert_size!(ForeignItem<'_>, 72);
|
||||||
static_assert_size!(ForeignItemKind<'_>, 40);
|
static_assert_size!(ForeignItemKind<'_>, 40);
|
||||||
|
@ -1094,8 +1094,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||||||
visitor.visit_expr(callee_expression);
|
visitor.visit_expr(callee_expression);
|
||||||
walk_list!(visitor, visit_expr, arguments);
|
walk_list!(visitor, visit_expr, arguments);
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(ref segment, arguments, _) => {
|
ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
|
||||||
visitor.visit_path_segment(expression.span, segment);
|
visitor.visit_path_segment(expression.span, segment);
|
||||||
|
visitor.visit_expr(receiver);
|
||||||
walk_list!(visitor, visit_expr, arguments);
|
walk_list!(visitor, visit_expr, arguments);
|
||||||
}
|
}
|
||||||
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
|
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
|
||||||
|
@ -1181,9 +1181,14 @@ impl<'a> State<'a> {
|
|||||||
self.print_call_post(args)
|
self.print_call_post(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) {
|
fn print_expr_method_call(
|
||||||
let base_args = &args[1..];
|
&mut self,
|
||||||
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
|
segment: &hir::PathSegment<'_>,
|
||||||
|
receiver: &hir::Expr<'_>,
|
||||||
|
args: &[hir::Expr<'_>],
|
||||||
|
) {
|
||||||
|
let base_args = args;
|
||||||
|
self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX);
|
||||||
self.word(".");
|
self.word(".");
|
||||||
self.print_ident(segment.ident);
|
self.print_ident(segment.ident);
|
||||||
|
|
||||||
@ -1394,8 +1399,8 @@ impl<'a> State<'a> {
|
|||||||
hir::ExprKind::Call(func, args) => {
|
hir::ExprKind::Call(func, args) => {
|
||||||
self.print_expr_call(func, args);
|
self.print_expr_call(func, args);
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(segment, args, _) => {
|
hir::ExprKind::MethodCall(segment, receiver, args, _) => {
|
||||||
self.print_expr_method_call(segment, args);
|
self.print_expr_method_call(segment, receiver, args);
|
||||||
}
|
}
|
||||||
hir::ExprKind::Binary(op, lhs, rhs) => {
|
hir::ExprKind::Binary(op, lhs, rhs) => {
|
||||||
self.print_expr_binary(op, lhs, rhs);
|
self.print_expr_binary(op, lhs, rhs);
|
||||||
@ -2393,9 +2398,9 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
|
|||||||
contains_exterior_struct_lit(x)
|
contains_exterior_struct_lit(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., exprs, _) => {
|
hir::ExprKind::MethodCall(_, receiver, ..) => {
|
||||||
// `X { y: 1 }.bar(...)`
|
// `X { y: 1 }.bar(...)`
|
||||||
contains_exterior_struct_lit(&exprs[0])
|
contains_exterior_struct_lit(receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -901,7 +901,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(segment, _, _) => {
|
hir::ExprKind::MethodCall(segment, ..) => {
|
||||||
if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
|
if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
let insertable: Option<_> = try {
|
let insertable: Option<_> = try {
|
||||||
@ -1132,7 +1132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
|
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
|
||||||
[generics.own_counts().lifetimes..];
|
[generics.own_counts().lifetimes..];
|
||||||
let span = match expr.kind {
|
let span = match expr.kind {
|
||||||
ExprKind::MethodCall(path, _, _) => path.ident.span,
|
ExprKind::MethodCall(path, ..) => path.ident.span,
|
||||||
_ => expr.span,
|
_ => expr.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1181,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
.any(|generics| generics.has_impl_trait())
|
.any(|generics| generics.has_impl_trait())
|
||||||
};
|
};
|
||||||
if let ExprKind::MethodCall(path, args, span) = expr.kind
|
if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
|
||||||
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
|
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
|
||||||
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
|
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
|
||||||
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
|
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
|
||||||
@ -1189,12 +1189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
&& !has_impl_trait(def_id)
|
&& !has_impl_trait(def_id)
|
||||||
{
|
{
|
||||||
let successor =
|
let successor =
|
||||||
args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
|
args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
|
||||||
let substs = self.infcx.resolve_vars_if_possible(substs);
|
let substs = self.infcx.resolve_vars_if_possible(substs);
|
||||||
self.update_infer_source(InferSource {
|
self.update_infer_source(InferSource {
|
||||||
span: path.ident.span,
|
span: path.ident.span,
|
||||||
kind: InferSourceKind::FullyQualifiedMethodCall {
|
kind: InferSourceKind::FullyQualifiedMethodCall {
|
||||||
receiver: args.first().unwrap(),
|
receiver,
|
||||||
successor,
|
successor,
|
||||||
substs,
|
substs,
|
||||||
def_id,
|
def_id,
|
||||||
|
@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We only care about method call expressions.
|
// We only care about method call expressions.
|
||||||
if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind {
|
if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
|
||||||
if call.ident.name != sym::into_iter {
|
if call.ident.name != sym::into_iter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -75,7 +75,6 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// As this is a method call expression, we have at least one argument.
|
// As this is a method call expression, we have at least one argument.
|
||||||
let receiver_arg = &args[0];
|
|
||||||
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
|
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
|
||||||
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
|
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
|
||||||
|
|
||||||
|
@ -2412,13 +2412,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
|
} else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
|
||||||
// Find problematic calls to `MaybeUninit::assume_init`.
|
// Find problematic calls to `MaybeUninit::assume_init`.
|
||||||
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
||||||
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
|
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
|
||||||
// This is a call to *some* method named `assume_init`.
|
// This is a call to *some* method named `assume_init`.
|
||||||
// See if the `self` parameter is one of the dangerous constructors.
|
// See if the `self` parameter is one of the dangerous constructors.
|
||||||
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
|
if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
|
||||||
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
|
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
|
||||||
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
|
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
|
||||||
match cx.tcx.get_diagnostic_name(def_id) {
|
match cx.tcx.get_diagnostic_name(def_id) {
|
||||||
|
@ -51,7 +51,7 @@ fn typeck_results_of_method_fn<'tcx>(
|
|||||||
expr: &Expr<'_>,
|
expr: &Expr<'_>,
|
||||||
) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
|
) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::MethodCall(segment, _, _)
|
ExprKind::MethodCall(segment, ..)
|
||||||
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
|
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
|
||||||
{
|
{
|
||||||
Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))
|
Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))
|
||||||
|
@ -44,9 +44,13 @@ fn in_macro(span: Span) -> bool {
|
|||||||
|
|
||||||
fn first_method_call<'tcx>(
|
fn first_method_call<'tcx>(
|
||||||
expr: &'tcx Expr<'tcx>,
|
expr: &'tcx Expr<'tcx>,
|
||||||
) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> {
|
) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> {
|
||||||
if let ExprKind::MethodCall(path, args, _) = &expr.kind {
|
if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind {
|
||||||
if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) }
|
if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((path, *receiver))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -59,15 +63,13 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match first_method_call(expr) {
|
match first_method_call(expr) {
|
||||||
Some((path, args)) if path.ident.name == sym::as_ptr => {
|
Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => {
|
||||||
let unwrap_arg = &args[0];
|
|
||||||
let as_ptr_span = path.ident.span;
|
let as_ptr_span = path.ident.span;
|
||||||
match first_method_call(unwrap_arg) {
|
match first_method_call(unwrap_arg) {
|
||||||
Some((path, args))
|
Some((path, receiver))
|
||||||
if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
|
if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
|
||||||
{
|
{
|
||||||
let source_arg = &args[0];
|
lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg);
|
||||||
lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg);
|
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
|||||||
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
// We only care about method calls.
|
// We only care about method calls.
|
||||||
let ExprKind::MethodCall(call, elements, _) = &expr.kind else {
|
let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
||||||
@ -81,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let receiver = &elements[0];
|
|
||||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||||
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||||
if receiver_ty != expr_ty {
|
if receiver_ty != expr_ty {
|
||||||
|
@ -1458,7 +1458,7 @@ impl InvalidAtomicOrdering {
|
|||||||
sym::AtomicI64,
|
sym::AtomicI64,
|
||||||
sym::AtomicI128,
|
sym::AtomicI128,
|
||||||
];
|
];
|
||||||
if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind
|
if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind
|
||||||
&& recognized_names.contains(&method_path.ident.name)
|
&& recognized_names.contains(&method_path.ident.name)
|
||||||
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
|
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
|
||||||
@ -1494,8 +1494,8 @@ impl InvalidAtomicOrdering {
|
|||||||
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
|
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
|
||||||
&& let Some((ordering_arg, invalid_ordering)) = match method {
|
&& let Some((ordering_arg, invalid_ordering)) = match method {
|
||||||
sym::load => Some((&args[1], sym::Release)),
|
sym::load => Some((&args[0], sym::Release)),
|
||||||
sym::store => Some((&args[2], sym::Acquire)),
|
sym::store => Some((&args[1], sym::Acquire)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg)
|
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg)
|
||||||
@ -1536,8 +1536,8 @@ impl InvalidAtomicOrdering {
|
|||||||
else {return };
|
else {return };
|
||||||
|
|
||||||
let fail_order_arg = match method {
|
let fail_order_arg = match method {
|
||||||
sym::fetch_update => &args[2],
|
sym::fetch_update => &args[1],
|
||||||
sym::compare_exchange | sym::compare_exchange_weak => &args[4],
|
sym::compare_exchange | sym::compare_exchange_weak => &args[3],
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -261,15 +261,19 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
|
|
||||||
let kind = match expr.kind {
|
let kind = match expr.kind {
|
||||||
// Here comes the interesting stuff:
|
// Here comes the interesting stuff:
|
||||||
hir::ExprKind::MethodCall(segment, ref args, fn_span) => {
|
hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => {
|
||||||
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
|
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
|
||||||
let expr = self.method_callee(expr, segment.ident.span, None);
|
let expr = self.method_callee(expr, segment.ident.span, None);
|
||||||
// When we apply adjustments to the receiver, use the span of
|
// When we apply adjustments to the receiver, use the span of
|
||||||
// the overall method call for better diagnostics. args[0]
|
// the overall method call for better diagnostics. args[0]
|
||||||
// is guaranteed to exist, since a method call always has a receiver.
|
// is guaranteed to exist, since a method call always has a receiver.
|
||||||
let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
|
let old_adjustment_span =
|
||||||
|
self.adjustment_span.replace((receiver.hir_id, expr_span));
|
||||||
info!("Using method span: {:?}", expr.span);
|
info!("Using method span: {:?}", expr.span);
|
||||||
let args = self.mirror_exprs(args);
|
let args = std::iter::once(receiver)
|
||||||
|
.chain(args.iter())
|
||||||
|
.map(|expr| self.mirror_expr(expr))
|
||||||
|
.collect();
|
||||||
self.adjustment_span = old_adjustment_span;
|
self.adjustment_span = old_adjustment_span;
|
||||||
ExprKind::Call {
|
ExprKind::Call {
|
||||||
ty: expr.ty,
|
ty: expr.ty,
|
||||||
|
@ -1039,9 +1039,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
self.propagate_through_expr(&f, succ)
|
self.propagate_through_expr(&f, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., ref args, _) => {
|
hir::ExprKind::MethodCall(.., receiver, ref args, _) => {
|
||||||
let succ = self.check_is_ty_uninhabited(expr, succ);
|
let succ = self.check_is_ty_uninhabited(expr, succ);
|
||||||
self.propagate_through_exprs(args, succ)
|
let succ = self.propagate_through_exprs(args, succ);
|
||||||
|
self.propagate_through_expr(receiver, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),
|
hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),
|
||||||
|
@ -803,6 +803,7 @@ impl<'tcx> DumpVisitor<'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ex: &'tcx hir::Expr<'tcx>,
|
ex: &'tcx hir::Expr<'tcx>,
|
||||||
seg: &'tcx hir::PathSegment<'tcx>,
|
seg: &'tcx hir::PathSegment<'tcx>,
|
||||||
|
receiver: &'tcx hir::Expr<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
) {
|
) {
|
||||||
debug!("process_method_call {:?} {:?}", ex, ex.span);
|
debug!("process_method_call {:?} {:?}", ex, ex.span);
|
||||||
@ -823,6 +824,7 @@ impl<'tcx> DumpVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// walk receiver and args
|
// walk receiver and args
|
||||||
|
self.visit_expr(receiver);
|
||||||
walk_list!(self, visit_expr, args);
|
walk_list!(self, visit_expr, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1343,7 +1345,9 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
|||||||
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
|
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
|
||||||
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
|
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args),
|
hir::ExprKind::MethodCall(ref seg, receiver, args, _) => {
|
||||||
|
self.process_method_call(ex, seg, receiver, args)
|
||||||
|
}
|
||||||
hir::ExprKind::Field(ref sub_ex, _) => {
|
hir::ExprKind::Field(ref sub_ex, _) => {
|
||||||
self.visit_expr(&sub_ex);
|
self.visit_expr(&sub_ex);
|
||||||
|
|
||||||
|
@ -590,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let closure_params_len = closure_fn_decl.inputs.len();
|
let closure_params_len = closure_fn_decl.inputs.len();
|
||||||
let (
|
let (
|
||||||
Some(Node::Expr(hir::Expr {
|
Some(Node::Expr(hir::Expr {
|
||||||
kind: hir::ExprKind::MethodCall(method_path, method_expr, _),
|
kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
|
||||||
..
|
..
|
||||||
})),
|
})),
|
||||||
1,
|
1,
|
||||||
@ -598,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
|
let self_ty = self.typeck_results.borrow().expr_ty(receiver);
|
||||||
let name = method_path.ident.name;
|
let name = method_path.ident.name;
|
||||||
let is_as_ref_able = match self_ty.peel_refs().kind() {
|
let is_as_ref_able = match self_ty.peel_refs().kind() {
|
||||||
ty::Adt(def, _) => {
|
ty::Adt(def, _) => {
|
||||||
@ -767,22 +767,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
if self.can_coerce(ref_ty, expected) {
|
if self.can_coerce(ref_ty, expected) {
|
||||||
let mut sugg_sp = sp;
|
let mut sugg_sp = sp;
|
||||||
if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind {
|
if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
|
||||||
let clone_trait =
|
let clone_trait =
|
||||||
self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
|
self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
|
||||||
if let ([arg], Some(true), sym::clone) = (
|
if args.is_empty()
|
||||||
&args[..],
|
&& self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|
||||||
self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|
|
||||||
|did| {
|
|did| {
|
||||||
let ai = self.tcx.associated_item(did);
|
let ai = self.tcx.associated_item(did);
|
||||||
ai.trait_container(self.tcx) == Some(clone_trait)
|
ai.trait_container(self.tcx) == Some(clone_trait)
|
||||||
},
|
},
|
||||||
),
|
) == Some(true)
|
||||||
segment.ident.name,
|
&& segment.ident.name == sym::clone
|
||||||
) {
|
{
|
||||||
// If this expression had a clone call when suggesting borrowing
|
// If this expression had a clone call when suggesting borrowing
|
||||||
// we want to suggest removing it because it'd now be unnecessary.
|
// we want to suggest removing it because it'd now be unnecessary.
|
||||||
sugg_sp = arg.span;
|
sugg_sp = receiver.span;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(src) = sm.span_to_snippet(sugg_sp) {
|
if let Ok(src) = sm.span_to_snippet(sugg_sp) {
|
||||||
|
@ -324,8 +324,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
|
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
|
||||||
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
|
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
|
||||||
ExprKind::MethodCall(segment, args, _) => {
|
ExprKind::MethodCall(segment, receiver, args, _) => {
|
||||||
self.check_method_call(expr, segment, args, expected)
|
self.check_method_call(expr, segment, receiver, args, expected)
|
||||||
}
|
}
|
||||||
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
|
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
|
||||||
ExprKind::Type(e, t) => {
|
ExprKind::Type(e, t) => {
|
||||||
@ -1195,13 +1195,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
segment: &hir::PathSegment<'_>,
|
segment: &hir::PathSegment<'_>,
|
||||||
|
rcvr: &'tcx hir::Expr<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let rcvr = &args[0];
|
|
||||||
let rcvr_t = self.check_expr(&rcvr);
|
let rcvr_t = self.check_expr(&rcvr);
|
||||||
// no need to check for bot/err -- callee does that
|
// no need to check for bot/err -- callee does that
|
||||||
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
|
let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
|
||||||
let span = segment.ident.span;
|
let span = segment.ident.span;
|
||||||
|
|
||||||
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
|
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
|
||||||
@ -1218,9 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
rcvr_t,
|
rcvr_t,
|
||||||
segment.ident,
|
segment.ident,
|
||||||
SelfSource::MethodCall(&args[0]),
|
SelfSource::MethodCall(rcvr),
|
||||||
error,
|
error,
|
||||||
Some(args),
|
Some((rcvr, args)),
|
||||||
) {
|
) {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
@ -1230,14 +1230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Call the generic checker.
|
// Call the generic checker.
|
||||||
self.check_method_argument_types(
|
self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected)
|
||||||
span,
|
|
||||||
expr,
|
|
||||||
method,
|
|
||||||
&args[1..],
|
|
||||||
DontTupleArguments,
|
|
||||||
expected,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr_cast(
|
fn check_expr_cast(
|
||||||
|
@ -987,7 +987,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if found != self.tcx.types.unit {
|
if found != self.tcx.types.unit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind {
|
if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
|
||||||
if self
|
if self
|
||||||
.typeck_results
|
.typeck_results
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -478,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
|
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
|
||||||
hir::ExprKind::MethodCall(path_segment, _, span) => {
|
hir::ExprKind::MethodCall(path_segment, _, _, span) => {
|
||||||
let ident_span = path_segment.ident.span;
|
let ident_span = path_segment.ident.span;
|
||||||
let ident_span = if let Some(args) = path_segment.args {
|
let ident_span = if let Some(args) = path_segment.args {
|
||||||
ident_span.with_hi(args.span_ext.hi())
|
ident_span.with_hi(args.span_ext.hi())
|
||||||
@ -530,13 +530,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.collect();
|
.collect();
|
||||||
let callee_expr = match &call_expr.peel_blocks().kind {
|
let callee_expr = match &call_expr.peel_blocks().kind {
|
||||||
hir::ExprKind::Call(callee, _) => Some(*callee),
|
hir::ExprKind::Call(callee, _) => Some(*callee),
|
||||||
hir::ExprKind::MethodCall(_, callee, _) => {
|
hir::ExprKind::MethodCall(_, receiver, ..) => {
|
||||||
if let Some((DefKind::AssocFn, def_id)) =
|
if let Some((DefKind::AssocFn, def_id)) =
|
||||||
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
|
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
|
||||||
&& let Some(assoc) = tcx.opt_associated_item(def_id)
|
&& let Some(assoc) = tcx.opt_associated_item(def_id)
|
||||||
&& assoc.fn_has_self_parameter
|
&& assoc.fn_has_self_parameter
|
||||||
{
|
{
|
||||||
Some(&callee[0])
|
Some(*receiver)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -1805,6 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
param,
|
param,
|
||||||
*call_hir_id,
|
*call_hir_id,
|
||||||
callee.span,
|
callee.span,
|
||||||
|
None,
|
||||||
args,
|
args,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -1823,7 +1824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(segment, args, ..) => {
|
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
|
||||||
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
@ -1834,6 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
param,
|
param,
|
||||||
hir_id,
|
hir_id,
|
||||||
segment.ident.span,
|
segment.ident.span,
|
||||||
|
Some(receiver),
|
||||||
args,
|
args,
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
@ -1901,7 +1903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
param_to_point_at: ty::GenericArg<'tcx>,
|
param_to_point_at: ty::GenericArg<'tcx>,
|
||||||
call_hir_id: hir::HirId,
|
call_hir_id: hir::HirId,
|
||||||
callee_span: Span,
|
callee_span: Span,
|
||||||
args: &[hir::Expr<'tcx>],
|
receiver: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let sig = self.tcx.fn_sig(def_id).skip_binder();
|
let sig = self.tcx.fn_sig(def_id).skip_binder();
|
||||||
let args_referencing_param: Vec<_> = sig
|
let args_referencing_param: Vec<_> = sig
|
||||||
@ -1910,9 +1913,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
|
.filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// If there's one field that references the given generic, great!
|
// If there's one field that references the given generic, great!
|
||||||
if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) {
|
if let [(idx, _)] = args_referencing_param.as_slice()
|
||||||
|
&& let Some(arg) = receiver
|
||||||
|
.map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
|
||||||
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
|
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
|
||||||
error.obligation.cause.map_code(|parent_code| {
|
error.obligation.cause.map_code(|parent_code| {
|
||||||
ObligationCauseCode::FunctionArgumentObligation {
|
ObligationCauseCode::FunctionArgumentObligation {
|
||||||
|
@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
found_ty: Ty<'tcx>,
|
found_ty: Ty<'tcx>,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
) {
|
) {
|
||||||
let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; };
|
let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
|
||||||
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
|
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
|
||||||
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
|
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
|
||||||
let results = self.typeck_results.borrow();
|
let results = self.typeck_results.borrow();
|
||||||
|
@ -434,7 +434,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
self.handle_uninhabited_return(expr);
|
self.handle_uninhabited_return(expr);
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(_, exprs, _) => {
|
ExprKind::MethodCall(_, receiver, exprs, _) => {
|
||||||
|
self.visit_expr(receiver);
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if precise {
|
if precise {
|
||||||
let args = args
|
let args = args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
|
let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
|
||||||
format!(
|
format!(
|
||||||
|
@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
error: MethodError<'tcx>,
|
error: MethodError<'tcx>,
|
||||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||||
// Avoid suggestions when we don't know what's going on.
|
// Avoid suggestions when we don't know what's going on.
|
||||||
if rcvr_ty.references_error() {
|
if rcvr_ty.references_error() {
|
||||||
@ -998,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
item_name,
|
item_name,
|
||||||
args.map(|args| args.len()),
|
args.map(|(_, args)| args.len() + 1),
|
||||||
source,
|
source,
|
||||||
out_of_scope_traits,
|
out_of_scope_traits,
|
||||||
&unsatisfied_predicates,
|
&unsatisfied_predicates,
|
||||||
@ -2310,7 +2310,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
|
|||||||
|
|
||||||
fn print_disambiguation_help<'tcx>(
|
fn print_disambiguation_help<'tcx>(
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
trait_name: String,
|
trait_name: String,
|
||||||
rcvr_ty: Ty<'_>,
|
rcvr_ty: Ty<'_>,
|
||||||
@ -2322,7 +2322,7 @@ fn print_disambiguation_help<'tcx>(
|
|||||||
fn_has_self_parameter: bool,
|
fn_has_self_parameter: bool,
|
||||||
) {
|
) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
|
let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
|
||||||
let args = format!(
|
let args = format!(
|
||||||
"({}{})",
|
"({}{})",
|
||||||
if rcvr_ty.is_region_ptr() {
|
if rcvr_ty.is_region_ptr() {
|
||||||
@ -2330,7 +2330,8 @@ fn print_disambiguation_help<'tcx>(
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
args.iter()
|
std::iter::once(receiver)
|
||||||
|
.chain(args.iter())
|
||||||
.map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
|
.map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
|
||||||
applicability = Applicability::HasPlaceholders;
|
applicability = Applicability::HasPlaceholders;
|
||||||
"_".to_owned()
|
"_".to_owned()
|
||||||
|
@ -233,8 +233,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||||||
self.consume_exprs(args);
|
self.consume_exprs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., args, _) => {
|
hir::ExprKind::MethodCall(.., receiver, args, _) => {
|
||||||
// callee.m(args)
|
// callee.m(args)
|
||||||
|
self.consume_expr(receiver);
|
||||||
self.consume_exprs(args);
|
self.consume_exprs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,13 +755,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||||||
num_assoc_fn_excess_args: usize,
|
num_assoc_fn_excess_args: usize,
|
||||||
num_trait_generics_except_self: usize,
|
num_trait_generics_except_self: usize,
|
||||||
) {
|
) {
|
||||||
if let hir::ExprKind::MethodCall(_, args, _) = expr.kind {
|
if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind {
|
||||||
assert_eq!(args.len(), 1);
|
assert_eq!(args.len(), 0);
|
||||||
if num_assoc_fn_excess_args == num_trait_generics_except_self {
|
if num_assoc_fn_excess_args == num_trait_generics_except_self {
|
||||||
if let Some(gen_args) = self.gen_args.span_ext()
|
if let Some(gen_args) = self.gen_args.span_ext()
|
||||||
&& let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
|
&& let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
|
||||||
&& let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) {
|
&& let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) {
|
||||||
let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args);
|
let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver);
|
||||||
err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
|
err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#![cfg_attr(feature = "as_crate", no_std)] // We are std!
|
#![cfg_attr(feature = "as_crate", no_std)] // We are std!
|
||||||
#![cfg_attr(
|
#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))]
|
||||||
feature = "as_crate",
|
|
||||||
feature(platform_intrinsics),
|
|
||||||
feature(portable_simd)
|
|
||||||
)]
|
|
||||||
#[cfg(not(feature = "as_crate"))]
|
#[cfg(not(feature = "as_crate"))]
|
||||||
use core::simd;
|
use core::simd;
|
||||||
#[cfg(feature = "as_crate")]
|
#[cfg(feature = "as_crate")]
|
||||||
|
@ -159,7 +159,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(path, _, call_span) => {
|
hir::ExprKind::MethodCall(path, _, _, call_span) => {
|
||||||
let types = tcx.typeck(ex.hir_id.owner);
|
let types = tcx.typeck(ex.hir_id.owner);
|
||||||
let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
|
let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
|
||||||
trace!("type_dependent_def_id({}) = None", ex.hir_id);
|
trace!("type_dependent_def_id({}) = None", ex.hir_id);
|
||||||
|
@ -121,15 +121,15 @@ hir-stats ----------------------------------------------------------------
|
|||||||
hir-stats ForeignItemRef 24 ( 0.2%) 1 24
|
hir-stats ForeignItemRef 24 ( 0.2%) 1 24
|
||||||
hir-stats Mod 32 ( 0.3%) 1 32
|
hir-stats Mod 32 ( 0.3%) 1 32
|
||||||
hir-stats ExprField 40 ( 0.4%) 1 40
|
hir-stats ExprField 40 ( 0.4%) 1 40
|
||||||
hir-stats TraitItemRef 56 ( 0.6%) 2 28
|
hir-stats TraitItemRef 56 ( 0.5%) 2 28
|
||||||
hir-stats Param 64 ( 0.6%) 2 32
|
hir-stats Param 64 ( 0.6%) 2 32
|
||||||
hir-stats Local 64 ( 0.6%) 1 64
|
hir-stats Local 64 ( 0.6%) 1 64
|
||||||
hir-stats InlineAsm 72 ( 0.7%) 1 72
|
hir-stats InlineAsm 72 ( 0.7%) 1 72
|
||||||
hir-stats ImplItemRef 72 ( 0.7%) 2 36
|
hir-stats ImplItemRef 72 ( 0.7%) 2 36
|
||||||
hir-stats FieldDef 96 ( 1.0%) 2 48
|
hir-stats FieldDef 96 ( 0.9%) 2 48
|
||||||
hir-stats Arm 96 ( 1.0%) 2 48
|
hir-stats Arm 96 ( 0.9%) 2 48
|
||||||
hir-stats Body 96 ( 1.0%) 3 32
|
hir-stats Body 96 ( 0.9%) 3 32
|
||||||
hir-stats Stmt 96 ( 1.0%) 3 32
|
hir-stats Stmt 96 ( 0.9%) 3 32
|
||||||
hir-stats - Local 32 ( 0.3%) 1
|
hir-stats - Local 32 ( 0.3%) 1
|
||||||
hir-stats - Semi 32 ( 0.3%) 1
|
hir-stats - Semi 32 ( 0.3%) 1
|
||||||
hir-stats - Expr 32 ( 0.3%) 1
|
hir-stats - Expr 32 ( 0.3%) 1
|
||||||
@ -144,34 +144,34 @@ hir-stats GenericBound 192 ( 1.9%) 4 48
|
|||||||
hir-stats - Trait 192 ( 1.9%) 4
|
hir-stats - Trait 192 ( 1.9%) 4
|
||||||
hir-stats WherePredicate 216 ( 2.1%) 3 72
|
hir-stats WherePredicate 216 ( 2.1%) 3 72
|
||||||
hir-stats - BoundPredicate 216 ( 2.1%) 3
|
hir-stats - BoundPredicate 216 ( 2.1%) 3
|
||||||
hir-stats Block 288 ( 2.9%) 6 48
|
hir-stats Block 288 ( 2.8%) 6 48
|
||||||
hir-stats GenericParam 400 ( 4.0%) 5 80
|
hir-stats GenericParam 400 ( 3.9%) 5 80
|
||||||
hir-stats Pat 440 ( 4.4%) 5 88
|
hir-stats Pat 440 ( 4.3%) 5 88
|
||||||
hir-stats - Wild 88 ( 0.9%) 1
|
hir-stats - Wild 88 ( 0.9%) 1
|
||||||
hir-stats - Struct 88 ( 0.9%) 1
|
hir-stats - Struct 88 ( 0.9%) 1
|
||||||
hir-stats - Binding 264 ( 2.6%) 3
|
hir-stats - Binding 264 ( 2.6%) 3
|
||||||
hir-stats Generics 560 ( 5.5%) 10 56
|
hir-stats Generics 560 ( 5.5%) 10 56
|
||||||
hir-stats Expr 672 ( 6.7%) 12 56
|
hir-stats Expr 768 ( 7.5%) 12 64
|
||||||
hir-stats - Path 56 ( 0.6%) 1
|
hir-stats - Path 64 ( 0.6%) 1
|
||||||
hir-stats - Struct 56 ( 0.6%) 1
|
hir-stats - Struct 64 ( 0.6%) 1
|
||||||
hir-stats - Match 56 ( 0.6%) 1
|
hir-stats - Match 64 ( 0.6%) 1
|
||||||
hir-stats - InlineAsm 56 ( 0.6%) 1
|
hir-stats - InlineAsm 64 ( 0.6%) 1
|
||||||
hir-stats - Lit 112 ( 1.1%) 2
|
hir-stats - Lit 128 ( 1.3%) 2
|
||||||
hir-stats - Block 336 ( 3.3%) 6
|
hir-stats - Block 384 ( 3.8%) 6
|
||||||
hir-stats Item 960 ( 9.5%) 12 80
|
hir-stats Item 960 ( 9.4%) 12 80
|
||||||
hir-stats - Trait 80 ( 0.8%) 1
|
hir-stats - Trait 80 ( 0.8%) 1
|
||||||
hir-stats - Enum 80 ( 0.8%) 1
|
hir-stats - Enum 80 ( 0.8%) 1
|
||||||
hir-stats - ExternCrate 80 ( 0.8%) 1
|
hir-stats - ExternCrate 80 ( 0.8%) 1
|
||||||
hir-stats - ForeignMod 80 ( 0.8%) 1
|
hir-stats - ForeignMod 80 ( 0.8%) 1
|
||||||
hir-stats - Impl 80 ( 0.8%) 1
|
hir-stats - Impl 80 ( 0.8%) 1
|
||||||
hir-stats - Fn 160 ( 1.6%) 2
|
hir-stats - Fn 160 ( 1.6%) 2
|
||||||
hir-stats - Use 400 ( 4.0%) 5
|
hir-stats - Use 400 ( 3.9%) 5
|
||||||
hir-stats Ty 1_080 (10.7%) 15 72
|
hir-stats Ty 1_080 (10.6%) 15 72
|
||||||
hir-stats - Ptr 72 ( 0.7%) 1
|
hir-stats - Ptr 72 ( 0.7%) 1
|
||||||
hir-stats - Rptr 72 ( 0.7%) 1
|
hir-stats - Rptr 72 ( 0.7%) 1
|
||||||
hir-stats - Path 936 ( 9.3%) 13
|
hir-stats - Path 936 ( 9.2%) 13
|
||||||
hir-stats Path 1_536 (15.2%) 32 48
|
hir-stats Path 1_536 (15.1%) 32 48
|
||||||
hir-stats PathSegment 2_240 (22.2%) 40 56
|
hir-stats PathSegment 2_240 (22.0%) 40 56
|
||||||
hir-stats ----------------------------------------------------------------
|
hir-stats ----------------------------------------------------------------
|
||||||
hir-stats Total 10_104
|
hir-stats Total 10_200
|
||||||
hir-stats
|
hir-stats
|
||||||
|
@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method
|
|||||||
impl<'tcx> LateLintPass<'tcx> for MyStructLint {
|
impl<'tcx> LateLintPass<'tcx> for MyStructLint {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||||
// Check our expr is calling a method
|
// Check our expr is calling a method
|
||||||
if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
|
if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
|
||||||
// Check the name of this method is `some_method`
|
// Check the name of this method is `some_method`
|
||||||
&& path.ident.name == sym!(some_method)
|
&& path.ident.name == sym!(some_method)
|
||||||
// Optionally, check the type of the self argument.
|
// Optionally, check the type of the self argument.
|
||||||
|
@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||||||
&& matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
|
&& matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
|
||||||
&& let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
|
&& let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
|
||||||
&& matches!(panic_expn, PanicExpn::Empty)
|
&& matches!(panic_expn, PanicExpn::Empty)
|
||||||
&& let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
|
&& let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
|
||||||
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
|
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
|
||||||
&& let result_type = result_type_with_refs.peel_refs()
|
&& let result_type = result_type_with_refs.peel_refs()
|
||||||
&& is_type_diagnostic_item(cx, result_type, sym::Result)
|
&& is_type_diagnostic_item(cx, result_type, sym::Result)
|
||||||
|
@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
|
|||||||
// do not lint if the closure is called using an iterator (see #1141)
|
// do not lint if the closure is called using an iterator (see #1141)
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Some(parent) = get_parent_expr(self.cx, expr);
|
if let Some(parent) = get_parent_expr(self.cx, expr);
|
||||||
if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
|
if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind;
|
||||||
let caller = self.cx.typeck_results().expr_ty(self_arg);
|
let caller = self.cx.typeck_results().expr_ty(self_arg);
|
||||||
if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
|
if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||||
if implements_trait(self.cx, caller, iter_id, &[]);
|
if implements_trait(self.cx, caller, iter_id, &[]);
|
||||||
@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
let span =
|
||||||
|
block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||||
if span.from_expansion() || expr.span.from_expansion() {
|
if span.from_expansion() || expr.span.from_expansion() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
|
ExprKind::MethodCall(path, receiver, [], _) => {
|
||||||
let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
|
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
|
||||||
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
|
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
|
||||||
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
|
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
|
||||||
{
|
{
|
||||||
@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
|||||||
let path: &str = path.ident.name.as_str();
|
let path: &str = path.ident.name.as_str();
|
||||||
a == path
|
a == path
|
||||||
})
|
})
|
||||||
.and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
|
.and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method)))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub(super) fn check(
|
|||||||
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
|
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
|
||||||
&& let ty::Int(from) = cast_from.kind()
|
&& let ty::Int(from) = cast_from.kind()
|
||||||
&& let ty::Uint(to) = cast_to.kind()
|
&& let ty::Uint(to) = cast_to.kind()
|
||||||
&& let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
|
&& let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
|
||||||
&& method_path.ident.name.as_str() == "abs"
|
&& method_path.ident.name.as_str() == "abs"
|
||||||
{
|
{
|
||||||
let span = if from.bit_width() == to.bit_width() {
|
let span = if from.bit_width() == to.bit_width() {
|
||||||
@ -37,7 +37,7 @@ pub(super) fn check(
|
|||||||
span,
|
span,
|
||||||
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
|
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
|
||||||
"replace with",
|
"replace with",
|
||||||
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
|
format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
|
|||||||
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
|
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
|
||||||
_ => nbits,
|
_ => nbits,
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(method, [left, right], _) => {
|
ExprKind::MethodCall(method, left, [right], _) => {
|
||||||
if signed {
|
if signed {
|
||||||
return nbits;
|
return nbits;
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
|
|||||||
};
|
};
|
||||||
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
|
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(method, [_, lo, hi], _) => {
|
ExprKind::MethodCall(method, _, [lo, hi], _) => {
|
||||||
if method.ident.as_str() == "clamp" {
|
if method.ident.as_str() == "clamp" {
|
||||||
//FIXME: make this a diagnostic item
|
//FIXME: make this a diagnostic item
|
||||||
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
|
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
|
||||||
@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
|
|||||||
}
|
}
|
||||||
nbits
|
nbits
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(method, [_value], _) => {
|
ExprKind::MethodCall(method, _value, [], _) => {
|
||||||
if method.ident.name.as_str() == "signum" {
|
if method.ident.name.as_str() == "signum" {
|
||||||
0 // do not lint if cast comes from a `signum` function
|
0 // do not lint if cast comes from a `signum` function
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
cx.typeck_results().expr_ty(expr),
|
cx.typeck_results().expr_ty(expr),
|
||||||
);
|
);
|
||||||
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
|
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
|
||||||
} else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
|
} else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
|
||||||
if method_path.ident.name == sym!(cast)
|
if method_path.ident.name == sym!(cast)
|
||||||
&& let Some(generic_args) = method_path.args
|
&& let Some(generic_args) = method_path.args
|
||||||
&& let [GenericArg::Type(cast_to)] = generic_args.args
|
&& let [GenericArg::Type(cast_to)] = generic_args.args
|
||||||
@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
match parent.kind {
|
match parent.kind {
|
||||||
ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
|
ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
|
||||||
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
|
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
|
||||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
|
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
|
||||||
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
|
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
|
||||||
|
@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't lint for the result of methods that always return non-negative values.
|
// Don't lint for the result of methods that always return non-negative values.
|
||||||
if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
|
if let ExprKind::MethodCall(path, ..) = cast_op.kind {
|
||||||
let mut method_name = path.ident.name.as_str();
|
let mut method_name = path.ident.name.as_str();
|
||||||
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
|
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
|
||||||
|
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if method_name == "unwrap";
|
if method_name == "unwrap";
|
||||||
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
|
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
|
||||||
if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
|
if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
|
||||||
then {
|
then {
|
||||||
method_name = inner_path.ident.name.as_str();
|
method_name = inner_path.ident.name.as_str();
|
||||||
}
|
}
|
||||||
|
@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
||||||
fn new(cx: &'a LateContext<'tcx>) -> Self {
|
fn new(cx: &'a LateContext<'tcx>) -> Self {
|
||||||
Self {
|
Self { ty_bounds: vec![TyBound::Nothing], cx }
|
||||||
ty_bounds: vec![TyBound::Nothing],
|
|
||||||
cx,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a passed literal has potential to cause fallback or not.
|
/// Check whether a passed literal has potential to cause fallback or not.
|
||||||
@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
ExprKind::MethodCall(_, args, _) => {
|
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||||
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||||
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
|
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
|
||||||
for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
|
for (expr, bound) in
|
||||||
|
iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
|
||||||
|
{
|
||||||
self.ty_bounds.push(TyBound::Ty(*bound));
|
self.ty_bounds.push(TyBound::Ty(*bound));
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
self.ty_bounds.pop();
|
self.ty_bounds.pop();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
ExprKind::Struct(_, fields, base) => {
|
ExprKind::Struct(_, fields, base) => {
|
||||||
let ty = self.cx.typeck_results().expr_ty(expr);
|
let ty = self.cx.typeck_results().expr_ty(expr);
|
||||||
@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
ExprKind::Lit(lit) => {
|
ExprKind::Lit(lit) => {
|
||||||
let ty = self.cx.typeck_results().expr_ty(expr);
|
let ty = self.cx.typeck_results().expr_ty(expr);
|
||||||
self.check_lit(lit, ty, expr.hir_id);
|
self.check_lit(lit, ty, expr.hir_id);
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
walk_expr(self, expr);
|
walk_expr(self, expr);
|
||||||
@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
self.ty_bounds.push(TyBound::Nothing);
|
self.ty_bounds.push(TyBound::Nothing);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => self.ty_bounds.push(TyBound::Nothing),
|
_ => self.ty_bounds.push(TyBound::Nothing),
|
||||||
}
|
}
|
||||||
|
@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>(
|
|||||||
expr: &'tcx Expr<'_>,
|
expr: &'tcx Expr<'_>,
|
||||||
) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
|
) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
|
||||||
let (def_id, arg) = match expr.kind {
|
let (def_id, arg) = match expr.kind {
|
||||||
ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
|
ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
|
||||||
ExprKind::Call(
|
ExprKind::Call(
|
||||||
Expr {
|
Expr {
|
||||||
kind: ExprKind::Path(path),
|
kind: ExprKind::Path(path),
|
||||||
@ -796,17 +796,16 @@ fn walk_parents<'tcx>(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
ExprKind::MethodCall(_, args, _) => {
|
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||||
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||||
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
if receiver.hir_id == child_id {
|
||||||
if i == 0 {
|
|
||||||
// Check for calls to trait methods where the trait is implemented on a reference.
|
// Check for calls to trait methods where the trait is implemented on a reference.
|
||||||
// Two cases need to be handled:
|
// Two cases need to be handled:
|
||||||
// * `self` methods on `&T` will never have auto-borrow
|
// * `self` methods on `&T` will never have auto-borrow
|
||||||
// * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
|
// * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
|
||||||
// priority.
|
// priority.
|
||||||
if e.hir_id != child_id {
|
if e.hir_id != child_id {
|
||||||
Position::ReborrowStable(precedence)
|
return Some(Position::ReborrowStable(precedence))
|
||||||
} else if let Some(trait_id) = cx.tcx.trait_of_item(id)
|
} else if let Some(trait_id) = cx.tcx.trait_of_item(id)
|
||||||
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
|
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
|
||||||
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
|
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
|
||||||
@ -830,23 +829,25 @@ fn walk_parents<'tcx>(
|
|||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Position::MethodReceiverRefImpl
|
return Some(Position::MethodReceiverRefImpl)
|
||||||
} else {
|
} else {
|
||||||
Position::MethodReceiver
|
return Some(Position::MethodReceiver)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
|
args.iter()
|
||||||
|
.position(|arg| arg.hir_id == child_id)
|
||||||
|
.map(|i| {
|
||||||
|
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
|
||||||
if let ty::Param(param_ty) = ty.kind() {
|
if let ty::Param(param_ty) = ty.kind() {
|
||||||
needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
|
needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
|
||||||
} else {
|
} else {
|
||||||
ty_auto_deref_stability(
|
ty_auto_deref_stability(
|
||||||
cx,
|
cx,
|
||||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
|
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
|
||||||
precedence,
|
precedence,
|
||||||
)
|
)
|
||||||
.position_for_arg()
|
.position_for_arg()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
|
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
|
||||||
|
@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
|||||||
|
|
||||||
// check for `unwrap`
|
// check for `unwrap`
|
||||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||||
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
|
||||||
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|
||||||
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
|
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
|
||||||
{
|
{
|
||||||
|
@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
|
|||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::MethodCall(
|
ExprKind::MethodCall(
|
||||||
_,
|
_,
|
||||||
[
|
|
||||||
map,
|
map,
|
||||||
|
[
|
||||||
Expr {
|
Expr {
|
||||||
kind: ExprKind::AddrOf(_, _, key),
|
kind: ExprKind::AddrOf(_, _, key),
|
||||||
span: key_span,
|
span: key_span,
|
||||||
@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
|
|||||||
value: &'tcx Expr<'tcx>,
|
value: &'tcx Expr<'tcx>,
|
||||||
}
|
}
|
||||||
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
|
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
|
||||||
if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
|
if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
|
||||||
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
||||||
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
|
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
|
||||||
Some(InsertExpr { map, key, value })
|
Some(InsertExpr { map, key, value })
|
||||||
|
@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
|||||||
if !is_adjusted(cx, &body.value);
|
if !is_adjusted(cx, &body.value);
|
||||||
if let ExprKind::Call(callee, args) = body.value.kind;
|
if let ExprKind::Call(callee, args) = body.value.kind;
|
||||||
if let ExprKind::Path(_) = callee.kind;
|
if let ExprKind::Path(_) = callee.kind;
|
||||||
if check_inputs(cx, body.params, args);
|
if check_inputs(cx, body.params, None, args);
|
||||||
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
|
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
|
||||||
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
|
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
|
||||||
.map_or(callee_ty, |id| cx.tcx.type_of(id));
|
.map_or(callee_ty, |id| cx.tcx.type_of(id));
|
||||||
@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
|||||||
|
|
||||||
if_chain!(
|
if_chain!(
|
||||||
if !is_adjusted(cx, &body.value);
|
if !is_adjusted(cx, &body.value);
|
||||||
if let ExprKind::MethodCall(path, args, _) = body.value.kind;
|
if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
|
||||||
if check_inputs(cx, body.params, args);
|
if check_inputs(cx, body.params, Some(receiver), args);
|
||||||
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
|
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
|
||||||
let substs = cx.typeck_results().node_substs(body.value.hir_id);
|
let substs = cx.typeck_results().node_substs(body.value.hir_id);
|
||||||
let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
|
let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
|
||||||
@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
|
fn check_inputs(
|
||||||
if params.len() != call_args.len() {
|
cx: &LateContext<'_>,
|
||||||
|
params: &[Param<'_>],
|
||||||
|
receiver: Option<&Expr<'_>>,
|
||||||
|
call_args: &[Expr<'_>],
|
||||||
|
) -> bool {
|
||||||
|
if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let binding_modes = cx.typeck_results().pat_binding_modes();
|
let binding_modes = cx.typeck_results().pat_binding_modes();
|
||||||
std::iter::zip(params, call_args).all(|(param, arg)| {
|
let check_inputs = |param: &Param<'_>, arg| {
|
||||||
match param.pat.kind {
|
match param.pat.kind {
|
||||||
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
|
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
|
||||||
_ => return false,
|
_ => return false,
|
||||||
@ -200,7 +205,9 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
|
|||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
|
||||||
|
.all(|(param, arg)| check_inputs(param, arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
|
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
|
||||||
|
@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
|||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
// match call to unwrap
|
// match call to unwrap
|
||||||
if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
|
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
|
||||||
if unwrap_fun.ident.name == sym::unwrap;
|
if unwrap_fun.ident.name == sym::unwrap;
|
||||||
// match call to write_fmt
|
// match call to write_fmt
|
||||||
if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
|
if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
|
||||||
if write_fun.ident.name == sym!(write_fmt);
|
if write_fun.ident.name == sym!(write_fmt);
|
||||||
// match calls to std::io::stdout() / std::io::stderr ()
|
// match calls to std::io::stdout() / std::io::stderr ()
|
||||||
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
|
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
|
||||||
|
@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
|
|||||||
|
|
||||||
// check for `unwrap`
|
// check for `unwrap`
|
||||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||||
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
|
||||||
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|
||||||
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
|
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
|
||||||
{
|
{
|
||||||
|
@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
|
|||||||
suggestion.maybe_par()
|
suggestion.maybe_par()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
|
||||||
if let Some(method) = get_specialized_log_method(cx, &args[1]) {
|
if let Some(method) = get_specialized_log_method(cx, &args[0]) {
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
SUBOPTIMAL_FLOPS,
|
SUBOPTIMAL_FLOPS,
|
||||||
expr.span,
|
expr.span,
|
||||||
"logarithm for bases 2, 10 and e can be computed more accurately",
|
"logarithm for bases 2, 10 and e can be computed more accurately",
|
||||||
"consider using",
|
"consider using",
|
||||||
format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
|
format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
|
|
||||||
// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
|
// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
|
||||||
// suggest usage of `(x + (y - 1)).ln_1p()` instead
|
// suggest usage of `(x + (y - 1)).ln_1p()` instead
|
||||||
fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
|
||||||
if let ExprKind::Binary(
|
if let ExprKind::Binary(
|
||||||
Spanned {
|
Spanned {
|
||||||
node: BinOpKind::Add, ..
|
node: BinOpKind::Add, ..
|
||||||
},
|
},
|
||||||
lhs,
|
lhs,
|
||||||
rhs,
|
rhs,
|
||||||
) = &args[0].kind
|
) = receiver.kind
|
||||||
{
|
{
|
||||||
let recv = match (
|
let recv = match (
|
||||||
constant(cx, cx.typeck_results(), lhs),
|
constant(cx, cx.typeck_results(), lhs),
|
||||||
@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
|
||||||
// Check receiver
|
// Check receiver
|
||||||
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
|
if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
|
||||||
let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
|
let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
|
||||||
"exp"
|
"exp"
|
||||||
} else if F32(2.0) == value || F64(2.0) == value {
|
} else if F32(2.0) == value || F64(2.0) == value {
|
||||||
@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
expr.span,
|
expr.span,
|
||||||
"exponent for bases 2 and e can be computed more accurately",
|
"exponent for bases 2 and e can be computed more accurately",
|
||||||
"consider using",
|
"consider using",
|
||||||
format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
|
format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check argument
|
// Check argument
|
||||||
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
|
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
|
||||||
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
|
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
|
||||||
(
|
(
|
||||||
SUBOPTIMAL_FLOPS,
|
SUBOPTIMAL_FLOPS,
|
||||||
"square-root of a number can be computed more efficiently and accurately",
|
"square-root of a number can be computed more efficiently and accurately",
|
||||||
format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
|
format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
|
||||||
)
|
)
|
||||||
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
|
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
|
||||||
(
|
(
|
||||||
IMPRECISE_FLOPS,
|
IMPRECISE_FLOPS,
|
||||||
"cube-root of a number can be computed more accurately",
|
"cube-root of a number can be computed more accurately",
|
||||||
format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
|
format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
|
||||||
)
|
)
|
||||||
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
|
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
|
||||||
(
|
(
|
||||||
@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
"exponentiation with integer powers can be computed more efficiently",
|
"exponentiation with integer powers can be computed more efficiently",
|
||||||
format!(
|
format!(
|
||||||
"{}.powi({})",
|
"{}.powi({})",
|
||||||
Sugg::hir(cx, &args[0], "..").maybe_par(),
|
Sugg::hir(cx, receiver, "..").maybe_par(),
|
||||||
numeric_literal::format(&exponent.to_string(), None, false)
|
numeric_literal::format(&exponent.to_string(), None, false)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
|
||||||
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
|
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
|
||||||
if value == Int(2) {
|
if value == Int(2) {
|
||||||
if let Some(parent) = get_parent_expr(cx, expr) {
|
if let Some(parent) = get_parent_expr(cx, expr) {
|
||||||
if let Some(grandparent) = get_parent_expr(cx, parent) {
|
if let Some(grandparent) = get_parent_expr(cx, parent) {
|
||||||
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
|
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
|
||||||
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
|
{
|
||||||
|
if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
"consider using",
|
"consider using",
|
||||||
format!(
|
format!(
|
||||||
"{}.mul_add({}, {})",
|
"{}.mul_add({}, {})",
|
||||||
Sugg::hir(cx, &args[0], "..").maybe_par(),
|
Sugg::hir(cx, receiver, "..").maybe_par(),
|
||||||
Sugg::hir(cx, &args[0], ".."),
|
Sugg::hir(cx, receiver, ".."),
|
||||||
Sugg::hir(cx, other_addend, ".."),
|
Sugg::hir(cx, other_addend, ".."),
|
||||||
),
|
),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
|
fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
|
||||||
if let ExprKind::Binary(
|
if let ExprKind::Binary(
|
||||||
Spanned {
|
Spanned {
|
||||||
node: BinOpKind::Add, ..
|
node: BinOpKind::Add, ..
|
||||||
},
|
},
|
||||||
add_lhs,
|
add_lhs,
|
||||||
add_rhs,
|
add_rhs,
|
||||||
) = args[0].kind
|
) = receiver.kind
|
||||||
{
|
{
|
||||||
// check if expression of the form x * x + y * y
|
// check if expression of the form x * x + y * y
|
||||||
if_chain! {
|
if_chain! {
|
||||||
@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
|
|||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(
|
if let ExprKind::MethodCall(
|
||||||
PathSegment { ident: lmethod_name, .. },
|
PathSegment { ident: lmethod_name, .. },
|
||||||
[largs_0, largs_1, ..],
|
largs_0, [largs_1, ..],
|
||||||
_
|
_
|
||||||
) = &add_lhs.kind;
|
) = &add_lhs.kind;
|
||||||
if let ExprKind::MethodCall(
|
if let ExprKind::MethodCall(
|
||||||
PathSegment { ident: rmethod_name, .. },
|
PathSegment { ident: rmethod_name, .. },
|
||||||
[rargs_0, rargs_1, ..],
|
rargs_0, [rargs_1, ..],
|
||||||
_
|
_
|
||||||
) = &add_rhs.kind;
|
) = &add_rhs.kind;
|
||||||
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
|
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
|
||||||
@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
|
fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
|
||||||
if let Some(message) = detect_hypot(cx, args) {
|
if let Some(message) = detect_hypot(cx, receiver) {
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
IMPRECISE_FLOPS,
|
IMPRECISE_FLOPS,
|
||||||
@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
if cx.typeck_results().expr_ty(lhs).is_floating_point();
|
if cx.typeck_results().expr_ty(lhs).is_floating_point();
|
||||||
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
|
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
|
||||||
if F32(1.0) == value || F64(1.0) == value;
|
if F32(1.0) == value || F64(1.0) == value;
|
||||||
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
|
if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
|
||||||
if cx.typeck_results().expr_ty(self_arg).is_floating_point();
|
if cx.typeck_results().expr_ty(self_arg).is_floating_point();
|
||||||
if path.ident.name.as_str() == "exp";
|
if path.ident.name.as_str() == "exp";
|
||||||
then {
|
then {
|
||||||
@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
) = &expr.kind
|
) = &expr.kind
|
||||||
{
|
{
|
||||||
if let Some(parent) = get_parent_expr(cx, expr) {
|
if let Some(parent) = get_parent_expr(cx, expr) {
|
||||||
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
|
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
|
||||||
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
|
if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
|
|
||||||
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
|
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
|
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
|
||||||
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
|
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
|
||||||
then {
|
then {
|
||||||
return method_name_a.as_str() == method_name_b.as_str() &&
|
return method_name_a.as_str() == method_name_b.as_str() &&
|
||||||
args_a.len() == args_b.len() &&
|
args_a.len() == args_b.len() &&
|
||||||
(
|
(
|
||||||
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
|
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
|
||||||
method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
|
method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
rhs,
|
rhs,
|
||||||
) = &expr.kind;
|
) = &expr.kind;
|
||||||
if are_same_base_logs(cx, lhs, rhs);
|
if are_same_base_logs(cx, lhs, rhs);
|
||||||
if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
|
if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
|
||||||
if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
|
if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
|
||||||
then {
|
then {
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ExprKind::MethodCall(path, args, _) = &expr.kind {
|
if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
|
||||||
let recv_ty = cx.typeck_results().expr_ty(&args[0]);
|
let recv_ty = cx.typeck_results().expr_ty(receiver);
|
||||||
|
|
||||||
if recv_ty.is_floating_point() {
|
if recv_ty.is_floating_point() {
|
||||||
match path.ident.name.as_str() {
|
match path.ident.name.as_str() {
|
||||||
"ln" => check_ln1p(cx, expr, args),
|
"ln" => check_ln1p(cx, expr, receiver),
|
||||||
"log" => check_log_base(cx, expr, args),
|
"log" => check_log_base(cx, expr, receiver, args),
|
||||||
"powf" => check_powf(cx, expr, args),
|
"powf" => check_powf(cx, expr, receiver, args),
|
||||||
"powi" => check_powi(cx, expr, args),
|
"powi" => check_powi(cx, expr, receiver, args),
|
||||||
"sqrt" => check_hypot(cx, expr, args),
|
"sqrt" => check_hypot(cx, expr, receiver),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
|
fn check_format_in_format_args(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
call_site: Span,
|
||||||
|
name: Symbol,
|
||||||
|
arg: &Expr<'_>,
|
||||||
|
) {
|
||||||
let expn_data = arg.span.ctxt().outer_expn_data();
|
let expn_data = arg.span.ctxt().outer_expn_data();
|
||||||
if expn_data.call_site.from_expansion() {
|
if expn_data.call_site.from_expansion() {
|
||||||
return;
|
return;
|
||||||
@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
|
|||||||
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
|
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !value.span.from_expansion();
|
if !value.span.from_expansion();
|
||||||
if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
|
if let ExprKind::MethodCall(_, receiver, [], _) = value.kind;
|
||||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
|
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
|
||||||
if is_diag_trait_item(cx, method_def_id, sym::ToString);
|
if is_diag_trait_item(cx, method_def_id, sym::ToString);
|
||||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||||
@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
|
|||||||
|
|
||||||
// Returns true if `hir_id` is referred to by multiple format params
|
// Returns true if `hir_id` is referred to by multiple format params
|
||||||
fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
|
fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
|
||||||
args.params()
|
args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
|
||||||
.filter(|param| param.value.hir_id == hir_id)
|
|
||||||
.at_most_one()
|
|
||||||
.is_err()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
|
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
|
||||||
@ -190,11 +192,7 @@ where
|
|||||||
let mut n_total = 0;
|
let mut n_total = 0;
|
||||||
let mut n_needed = 0;
|
let mut n_needed = 0;
|
||||||
loop {
|
loop {
|
||||||
if let Some(Adjustment {
|
if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
|
||||||
kind: Adjust::Deref(overloaded_deref),
|
|
||||||
target,
|
|
||||||
}) = iter.next()
|
|
||||||
{
|
|
||||||
n_total += 1;
|
n_total += 1;
|
||||||
if overloaded_deref.is_some() {
|
if overloaded_deref.is_some() {
|
||||||
n_needed = n_total;
|
n_needed = n_total;
|
||||||
|
@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
|
|||||||
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
// Get the hir_id of the object we are calling the method on
|
// Get the hir_id of the object we are calling the method on
|
||||||
if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
|
if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
|
||||||
// Is the method to_string() ?
|
// Is the method to_string() ?
|
||||||
if path.ident.name == sym::to_string;
|
if path.ident.name == sym::to_string;
|
||||||
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
|
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
|
||||||
|
@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||||||
impl<'tcx> LateLintPass<'tcx> for FormatPushString {
|
impl<'tcx> LateLintPass<'tcx> for FormatPushString {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
let arg = match expr.kind {
|
let arg = match expr.kind {
|
||||||
ExprKind::MethodCall(_, [_, arg], _) => {
|
ExprKind::MethodCall(_, _, [arg], _) => {
|
||||||
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
|
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
|
||||||
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
||||||
arg
|
arg
|
||||||
|
@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
Call(_, args) | MethodCall(_, args, _) => {
|
Call(_, args) => {
|
||||||
let mut tys = DefIdSet::default();
|
let mut tys = DefIdSet::default();
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
|
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
|
||||||
@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
|
|||||||
tys.clear();
|
tys.clear();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
MethodCall(_, receiver, args, _) => {
|
||||||
|
let mut tys = DefIdSet::default();
|
||||||
|
for arg in std::iter::once(receiver).chain(args.iter()) {
|
||||||
|
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
|
||||||
|
&& is_mutable_ty(
|
||||||
|
self.cx,
|
||||||
|
self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
|
||||||
|
arg.span,
|
||||||
|
&mut tys,
|
||||||
|
)
|
||||||
|
&& is_mutated_static(arg)
|
||||||
|
{
|
||||||
|
self.mutates_static = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tys.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
|
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
|
||||||
self.mutates_static |= is_mutated_static(target);
|
self.mutates_static |= is_mutated_static(target);
|
||||||
},
|
},
|
||||||
|
@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ExprKind::MethodCall(_, args, _) => {
|
hir::ExprKind::MethodCall(_, receiver, args, _) => {
|
||||||
let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
|
let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
|
||||||
let base_type = self.cx.tcx.type_of(def_id);
|
let base_type = self.cx.tcx.type_of(def_id);
|
||||||
|
|
||||||
if type_is_unsafe_function(self.cx, base_type) {
|
if type_is_unsafe_function(self.cx, base_type) {
|
||||||
|
self.check_arg(receiver);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.check_arg(arg);
|
self.check_arg(arg);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
|
|||||||
|
|
||||||
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
|
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
|
||||||
if path.ident.as_str() == "lock";
|
if path.ident.as_str() == "lock";
|
||||||
let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
|
let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
|
||||||
if is_type_diagnostic_item(cx, ty, sym::Mutex);
|
if is_type_diagnostic_item(cx, ty, sym::Mutex);
|
||||||
|
@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
|
|||||||
MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
|
MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
|
||||||
Finite => {
|
Finite => {
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
span_lint(cx, lint, expr.span, msg);
|
span_lint(cx, lint, expr.span, msg);
|
||||||
}
|
}
|
||||||
@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First};
|
|||||||
/// is an upper bound, e.g., some methods can return a possibly
|
/// is an upper bound, e.g., some methods can return a possibly
|
||||||
/// infinite iterator at worst, e.g., `take_while`.
|
/// infinite iterator at worst, e.g., `take_while`.
|
||||||
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
|
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
|
||||||
("zip", 2, All, Infinite),
|
("zip", 1, All, Infinite),
|
||||||
("chain", 2, Any, Infinite),
|
("chain", 1, Any, Infinite),
|
||||||
("cycle", 1, Always, Infinite),
|
("cycle", 0, Always, Infinite),
|
||||||
("map", 2, First, Infinite),
|
("map", 1, First, Infinite),
|
||||||
("by_ref", 1, First, Infinite),
|
("by_ref", 0, First, Infinite),
|
||||||
("cloned", 1, First, Infinite),
|
("cloned", 0, First, Infinite),
|
||||||
("rev", 1, First, Infinite),
|
("rev", 0, First, Infinite),
|
||||||
("inspect", 1, First, Infinite),
|
("inspect", 0, First, Infinite),
|
||||||
("enumerate", 1, First, Infinite),
|
("enumerate", 0, First, Infinite),
|
||||||
("peekable", 2, First, Infinite),
|
("peekable", 1, First, Infinite),
|
||||||
("fuse", 1, First, Infinite),
|
("fuse", 0, First, Infinite),
|
||||||
("skip", 2, First, Infinite),
|
("skip", 1, First, Infinite),
|
||||||
("skip_while", 1, First, Infinite),
|
("skip_while", 0, First, Infinite),
|
||||||
("filter", 2, First, Infinite),
|
("filter", 1, First, Infinite),
|
||||||
("filter_map", 2, First, Infinite),
|
("filter_map", 1, First, Infinite),
|
||||||
("flat_map", 2, First, Infinite),
|
("flat_map", 1, First, Infinite),
|
||||||
("unzip", 1, First, Infinite),
|
("unzip", 0, First, Infinite),
|
||||||
("take_while", 2, First, MaybeInfinite),
|
("take_while", 1, First, MaybeInfinite),
|
||||||
("scan", 3, First, MaybeInfinite),
|
("scan", 2, First, MaybeInfinite),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::MethodCall(method, args, _) => {
|
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||||
for &(name, len, heuristic, cap) in &HEURISTICS {
|
for &(name, len, heuristic, cap) in &HEURISTICS {
|
||||||
if method.ident.name.as_str() == name && args.len() == len {
|
if method.ident.name.as_str() == name && args.len() == len {
|
||||||
return (match heuristic {
|
return (match heuristic {
|
||||||
Always => Infinite,
|
Always => Infinite,
|
||||||
First => is_infinite(cx, &args[0]),
|
First => is_infinite(cx, receiver),
|
||||||
Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
|
Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
|
||||||
All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
|
All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
|
||||||
})
|
})
|
||||||
.and(cap);
|
.and(cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if method.ident.name == sym!(flat_map) && args.len() == 2 {
|
if method.ident.name == sym!(flat_map) && args.len() == 1 {
|
||||||
if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
|
if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
|
||||||
let body = cx.tcx.hir().body(body);
|
let body = cx.tcx.hir().body(body);
|
||||||
return is_infinite(cx, &body.value);
|
return is_infinite(cx, &body.value);
|
||||||
}
|
}
|
||||||
@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
|||||||
/// the names and argument lengths of methods that *may* exhaust their
|
/// the names and argument lengths of methods that *may* exhaust their
|
||||||
/// iterators
|
/// iterators
|
||||||
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
|
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
|
||||||
("find", 2),
|
("find", 1),
|
||||||
("rfind", 2),
|
("rfind", 1),
|
||||||
("position", 2),
|
("position", 1),
|
||||||
("rposition", 2),
|
("rposition", 1),
|
||||||
("any", 2),
|
("any", 1),
|
||||||
("all", 2),
|
("all", 1),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// the names and argument lengths of methods that *always* exhaust
|
/// the names and argument lengths of methods that *always* exhaust
|
||||||
/// their iterators
|
/// their iterators
|
||||||
const COMPLETING_METHODS: [(&str, usize); 12] = [
|
const COMPLETING_METHODS: [(&str, usize); 12] = [
|
||||||
("count", 1),
|
("count", 0),
|
||||||
("fold", 3),
|
("fold", 2),
|
||||||
("for_each", 2),
|
("for_each", 1),
|
||||||
("partition", 2),
|
("partition", 1),
|
||||||
("max", 1),
|
("max", 0),
|
||||||
("max_by", 2),
|
("max_by", 1),
|
||||||
("max_by_key", 2),
|
("max_by_key", 1),
|
||||||
("min", 1),
|
("min", 0),
|
||||||
("min_by", 2),
|
("min_by", 1),
|
||||||
("min_by_key", 2),
|
("min_by_key", 1),
|
||||||
("sum", 1),
|
("sum", 0),
|
||||||
("product", 1),
|
("product", 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// the paths of types that are known to be infinitely allocating
|
/// the paths of types that are known to be infinitely allocating
|
||||||
@ -218,26 +218,24 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
|
|||||||
|
|
||||||
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::MethodCall(method, args, _) => {
|
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||||
for &(name, len) in &COMPLETING_METHODS {
|
for &(name, len) in &COMPLETING_METHODS {
|
||||||
if method.ident.name.as_str() == name && args.len() == len {
|
if method.ident.name.as_str() == name && args.len() == len {
|
||||||
return is_infinite(cx, &args[0]);
|
return is_infinite(cx, receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
|
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
|
||||||
if method.ident.name.as_str() == name && args.len() == len {
|
if method.ident.name.as_str() == name && args.len() == len {
|
||||||
return MaybeInfinite.and(is_infinite(cx, &args[0]));
|
return MaybeInfinite.and(is_infinite(cx, receiver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if method.ident.name == sym!(last) && args.len() == 1 {
|
if method.ident.name == sym!(last) && args.is_empty() {
|
||||||
let not_double_ended = cx
|
let not_double_ended =
|
||||||
.tcx
|
cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
|
||||||
.get_diagnostic_item(sym::DoubleEndedIterator)
|
!implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
|
||||||
.map_or(false, |id| {
|
|
||||||
!implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
|
|
||||||
});
|
});
|
||||||
if not_double_ended {
|
if not_double_ended {
|
||||||
return is_infinite(cx, &args[0]);
|
return is_infinite(cx, receiver);
|
||||||
}
|
}
|
||||||
} else if method.ident.name == sym!(collect) {
|
} else if method.ident.name == sym!(collect) {
|
||||||
let ty = cx.typeck_results().expr_ty(expr);
|
let ty = cx.typeck_results().expr_ty(expr);
|
||||||
@ -245,7 +243,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
|
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
|
||||||
{
|
{
|
||||||
return is_infinite(cx, &args[0]);
|
return is_infinite(cx, receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
|
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
|
||||||
if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
|
if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
|
||||||
// check if we are in an is_empty() method
|
// check if we are in an is_empty() method
|
||||||
if let Some(name) = get_item_name(cx, method) {
|
if let Some(name) = get_item_name(cx, method) {
|
||||||
if name.as_str() == "is_empty" {
|
if name.as_str() == "is_empty" {
|
||||||
@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
|
check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
|
||||||
} else {
|
} else {
|
||||||
check_empty_expr(cx, span, method, lit, op);
|
check_empty_expr(cx, span, method, lit, op);
|
||||||
}
|
}
|
||||||
@ -388,6 +388,7 @@ fn check_len(
|
|||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
method_name: Symbol,
|
method_name: Symbol,
|
||||||
|
receiver: &Expr<'_>,
|
||||||
args: &[Expr<'_>],
|
args: &[Expr<'_>],
|
||||||
lit: &LitKind,
|
lit: &LitKind,
|
||||||
op: &str,
|
op: &str,
|
||||||
@ -399,7 +400,7 @@ fn check_len(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
|
if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
@ -410,7 +411,7 @@ fn check_len(
|
|||||||
format!(
|
format!(
|
||||||
"{}{}.is_empty()",
|
"{}{}.is_empty()",
|
||||||
op,
|
op,
|
||||||
snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
|
snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
|
||||||
),
|
),
|
||||||
applicability,
|
applicability,
|
||||||
);
|
);
|
||||||
|
@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||||||
|
|
||||||
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
|
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(method, [recv], _) = end.kind;
|
if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
|
||||||
if method.ident.name == sym::len;
|
if method.ident.name == sym::len;
|
||||||
if path_to_local(recv) == path_to_local(base);
|
if path_to_local(recv) == path_to_local(base);
|
||||||
then {
|
then {
|
||||||
@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
|
|||||||
|
|
||||||
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
|
if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
|
||||||
if method.ident.name == sym::clone;
|
if method.ident.name == sym::clone;
|
||||||
then { arg } else { expr }
|
then { arg } else { expr }
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
|||||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
|
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
|
||||||
if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
|
if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
|
||||||
if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
|
if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
|
||||||
if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
|
if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
|
||||||
if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
|
if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
|
||||||
|
@ -742,7 +742,7 @@ fn check_for_loop<'tcx>(
|
|||||||
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
|
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
|
||||||
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
|
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
|
||||||
|
|
||||||
if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
|
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
|
||||||
let method_name = method.ident.as_str();
|
let method_name = method.ident.as_str();
|
||||||
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
|
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
|
||||||
match method_name {
|
match method_name {
|
||||||
|
@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
|||||||
}
|
}
|
||||||
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(method, args, _) = expr.kind;
|
if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
|
||||||
if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
|
if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
|
||||||
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
|
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
|
||||||
then {
|
then {
|
||||||
let ty = cx.typeck_results().expr_ty(&args[0]);
|
let ty = cx.typeck_results().expr_ty(receiver);
|
||||||
let mut applicability = Applicability::MaybeIncorrect;
|
let mut applicability = Applicability::MaybeIncorrect;
|
||||||
let is_empty_sugg = "next().is_none()".to_string();
|
let is_empty_sugg = "next().is_none()".to_string();
|
||||||
let method_name = method.ident.name.as_str();
|
let method_name = method.ident.name.as_str();
|
||||||
@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
|
|||||||
"len" => "count()".to_string(),
|
"len" => "count()".to_string(),
|
||||||
"is_empty" => is_empty_sugg,
|
"is_empty" => is_empty_sugg,
|
||||||
"contains" => {
|
"contains" => {
|
||||||
let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
|
let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
|
||||||
let (arg, pred) = contains_arg
|
let (arg, pred) = contains_arg
|
||||||
.strip_prefix('&')
|
.strip_prefix('&')
|
||||||
.map_or(("&x", &*contains_arg), |s| ("x", s));
|
.map_or(("&x", &*contains_arg), |s| ("x", s));
|
||||||
@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
|
|||||||
if let StmtKind::Local(local) = stmt.kind;
|
if let StmtKind::Local(local) = stmt.kind;
|
||||||
if let PatKind::Binding(_, id, ..) = local.pat.kind;
|
if let PatKind::Binding(_, id, ..) = local.pat.kind;
|
||||||
if let Some(init_expr) = local.init;
|
if let Some(init_expr) = local.init;
|
||||||
if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
|
if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
|
||||||
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
|
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
|
||||||
let ty = cx.typeck_results().expr_ty(init_expr);
|
let ty = cx.typeck_results().expr_ty(init_expr);
|
||||||
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
|
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
|
||||||
@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
|
|||||||
|
|
||||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||||
// Check function calls on our collection
|
// Check function calls on our collection
|
||||||
if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
|
if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
|
||||||
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
|
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
|
||||||
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
|
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
|
||||||
self.visit_expr(recv);
|
self.visit_expr(recv);
|
||||||
|
@ -188,7 +188,7 @@ pub(super) fn check<'tcx>(
|
|||||||
|
|
||||||
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
|
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
|
if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
|
||||||
if method.ident.name == sym::len;
|
if method.ident.name == sym::len;
|
||||||
if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
|
if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
|
||||||
if path.segments.len() == 1;
|
if path.segments.len() == 1;
|
||||||
@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
// a range index op
|
// a range index op
|
||||||
if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
|
if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
|
||||||
if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
|
if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
|
||||||
|| (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
|
|| (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
|
||||||
if !self.check(args_1, args_0, expr);
|
if !self.check(args_1, args_0, expr);
|
||||||
@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(_, args, _) => {
|
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||||
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||||
for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
|
for (ty, expr) in iter::zip(
|
||||||
|
self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
|
||||||
|
std::iter::once(receiver).chain(args.iter()),
|
||||||
|
) {
|
||||||
self.prefer_mutable = false;
|
self.prefer_mutable = false;
|
||||||
if let ty::Ref(_, _, mutbl) = *ty.kind() {
|
if let ty::Ref(_, _, mutbl) = *ty.kind() {
|
||||||
if mutbl == Mutability::Mut {
|
if mutbl == Mutability::Mut {
|
||||||
|
@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
|||||||
| ExprKind::Repeat(e, _)
|
| ExprKind::Repeat(e, _)
|
||||||
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
|
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
|
||||||
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
|
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
|
||||||
ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
|
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
|
||||||
never_loop_expr_all(&mut es.iter(), main_loop_id)
|
ExprKind::MethodCall(_, receiver, es, _) => {
|
||||||
|
never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
|
||||||
},
|
},
|
||||||
ExprKind::Struct(_, fields, base) => {
|
ExprKind::Struct(_, fields, base) => {
|
||||||
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
|
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
|
||||||
|
@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
|
|||||||
if_chain! {
|
if_chain! {
|
||||||
// Extract method being called
|
// Extract method being called
|
||||||
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
|
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
|
||||||
if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
|
if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
|
||||||
// Figure out the parameters for the method call
|
// Figure out the parameters for the method call
|
||||||
if let Some(self_expr) = args.get(0);
|
if let Some(pushed_item) = args.get(0);
|
||||||
if let Some(pushed_item) = args.get(1);
|
|
||||||
// Check that the method being called is push() on a Vec
|
// Check that the method being called is push() on a Vec
|
||||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
|
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
|
||||||
if path.ident.name.as_str() == "push";
|
if path.ident.name.as_str() == "push";
|
||||||
|
@ -35,32 +35,29 @@ pub(super) fn check<'tcx>(
|
|||||||
) => (arg, "&mut "),
|
) => (arg, "&mut "),
|
||||||
ExprKind::MethodCall(
|
ExprKind::MethodCall(
|
||||||
method,
|
method,
|
||||||
[
|
|
||||||
Expr {
|
Expr {
|
||||||
kind: ExprKind::Array([arg]),
|
kind: ExprKind::Array([arg]),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
],
|
[],
|
||||||
_,
|
_,
|
||||||
) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
|
) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
|
||||||
ExprKind::MethodCall(
|
ExprKind::MethodCall(
|
||||||
method,
|
method,
|
||||||
[
|
|
||||||
Expr {
|
Expr {
|
||||||
kind: ExprKind::Array([arg]),
|
kind: ExprKind::Array([arg]),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
],
|
[],
|
||||||
_,
|
_,
|
||||||
) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
|
) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
|
||||||
ExprKind::MethodCall(
|
ExprKind::MethodCall(
|
||||||
method,
|
method,
|
||||||
[
|
|
||||||
Expr {
|
Expr {
|
||||||
kind: ExprKind::Array([arg]),
|
kind: ExprKind::Array([arg]),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
],
|
[],
|
||||||
_,
|
_,
|
||||||
) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
|
) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
|
||||||
// Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
|
// Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
|
||||||
|
@ -11,7 +11,14 @@ use rustc_lint::LateContext;
|
|||||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
||||||
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
|
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
|
||||||
([stmt, stmts @ ..], expr) => {
|
([stmt, stmts @ ..], expr) => {
|
||||||
if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
|
if let StmtKind::Local(&Local {
|
||||||
|
init: Some(e),
|
||||||
|
els: None,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| StmtKind::Semi(e)
|
||||||
|
| StmtKind::Expr(e) = stmt.kind
|
||||||
|
{
|
||||||
(e, !stmts.is_empty() || expr.is_some())
|
(e, !stmts.is_empty() || expr.is_some())
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
if let Res::Def(_, pat_did) = pat_path.res;
|
if let Res::Def(_, pat_did) = pat_path.res;
|
||||||
if match_def_path(cx, pat_did, &paths::OPTION_SOME);
|
if match_def_path(cx, pat_did, &paths::OPTION_SOME);
|
||||||
// check for call to `Iterator::next`
|
// check for call to `Iterator::next`
|
||||||
if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
|
if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
|
||||||
if method_name.ident.name == sym::next;
|
if method_name.ident.name == sym::next;
|
||||||
if is_trait_method(cx, let_expr, sym::Iterator);
|
if is_trait_method(cx, let_expr, sym::Iterator);
|
||||||
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
|
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
|
||||||
|
@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri
|
|||||||
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
|
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
|
||||||
if let ExprKind::Cast(..) = expr.kind {
|
if let ExprKind::Cast(..) = expr.kind {
|
||||||
true
|
true
|
||||||
} else if let ExprKind::MethodCall(path, [_], _) = expr.kind
|
} else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
|
||||||
&& path.ident.name == rustc_span::sym::try_into
|
&& path.ident.name == rustc_span::sym::try_into
|
||||||
{
|
{
|
||||||
// This is only called for `usize` which implements `TryInto`. Therefore,
|
// This is only called for `usize` which implements `TryInto`. Therefore,
|
||||||
|
@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
|
|||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||||
if let Some(parent_expr) = get_parent_expr(cx, expr)
|
if let Some(parent_expr) = get_parent_expr(cx, expr)
|
||||||
&& let Assign(left_expr, collect_expr, _) = &parent_expr.kind
|
&& let Assign(left_expr, collect_expr, _) = &parent_expr.kind
|
||||||
&& let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
|
&& let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
|
||||||
&& seg.args.is_none()
|
&& seg.args.is_none()
|
||||||
&& let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
|
&& let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
|
||||||
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
|
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
|
||||||
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
|
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
|
||||||
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
|
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
|
||||||
@ -87,10 +87,10 @@ fn check_into_iter(
|
|||||||
target_expr: &hir::Expr<'_>,
|
target_expr: &hir::Expr<'_>,
|
||||||
msrv: Option<RustcVersion>,
|
msrv: Option<RustcVersion>,
|
||||||
) {
|
) {
|
||||||
if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
|
if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
|
||||||
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
||||||
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
||||||
&& let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
|
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
|
||||||
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
|
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
|
||||||
&& match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
|
&& match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
|
||||||
&& match_acceptable_type(cx, left_expr, msrv)
|
&& match_acceptable_type(cx, left_expr, msrv)
|
||||||
@ -106,14 +106,14 @@ fn check_iter(
|
|||||||
target_expr: &hir::Expr<'_>,
|
target_expr: &hir::Expr<'_>,
|
||||||
msrv: Option<RustcVersion>,
|
msrv: Option<RustcVersion>,
|
||||||
) {
|
) {
|
||||||
if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
|
if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
|
||||||
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
||||||
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|
||||||
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
|
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
|
||||||
&& let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
|
&& let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
|
||||||
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
|
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
|
||||||
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
||||||
&& let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
|
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
|
||||||
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
|
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
|
||||||
&& match_acceptable_def_path(cx, iter_expr_def_id)
|
&& match_acceptable_def_path(cx, iter_expr_def_id)
|
||||||
&& match_acceptable_type(cx, left_expr, msrv)
|
&& match_acceptable_type(cx, left_expr, msrv)
|
||||||
@ -130,13 +130,13 @@ fn check_to_owned(
|
|||||||
msrv: Option<RustcVersion>,
|
msrv: Option<RustcVersion>,
|
||||||
) {
|
) {
|
||||||
if meets_msrv(msrv, msrvs::STRING_RETAIN)
|
if meets_msrv(msrv, msrvs::STRING_RETAIN)
|
||||||
&& let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
|
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
|
||||||
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
|
||||||
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
|
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
|
||||||
&& let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
|
&& let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
|
||||||
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
|
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
|
||||||
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
|
||||||
&& let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
|
&& let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
|
||||||
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
|
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
|
||||||
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
|
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
|
||||||
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
|
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
|
||||||
@ -147,7 +147,7 @@ fn check_to_owned(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
|
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
|
||||||
if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
|
if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
|
||||||
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
|
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
|
||||||
&& let filter_body = cx.tcx.hir().body(body)
|
&& let filter_body = cx.tcx.hir().body(body)
|
||||||
&& let [filter_params] = filter_body.params
|
&& let [filter_params] = filter_body.params
|
||||||
|
@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew {
|
|||||||
ExprKind::Call(func, args) => {
|
ExprKind::Call(func, args) => {
|
||||||
parse_call(cx, expr.span, func, args);
|
parse_call(cx, expr.span, func, args);
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(path_segment, args, _) => {
|
ExprKind::MethodCall(path_segment, receiver, ..) => {
|
||||||
parse_method_call(cx, expr.span, path_segment, args);
|
parse_method_call(cx, expr.span, path_segment, receiver);
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to parse an expression as a method call, emitting the warning if necessary.
|
/// Tries to parse an expression as a method call, emitting the warning if necessary.
|
||||||
fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
|
fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
|
||||||
if args.is_empty() {
|
|
||||||
// When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ident = path_segment.ident.as_str();
|
let ident = path_segment.ident.as_str();
|
||||||
let method_arg_kind = &args[0].kind;
|
let method_arg_kind = &receiver.kind;
|
||||||
if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
|
if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
|
||||||
warn_then_suggest(cx, span);
|
warn_then_suggest(cx, span);
|
||||||
} else if let ExprKind::Call(func, args) = method_arg_kind {
|
} else if let ExprKind::Call(func, args) = method_arg_kind {
|
||||||
|
@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
|||||||
|
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
||||||
if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
|
if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
|
||||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
|
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
|
||||||
if let ExprKind::Path(target_path) = &target_arg.kind;
|
if let ExprKind::Path(target_path) = &target_arg.kind;
|
||||||
then {
|
then {
|
||||||
@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
|||||||
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
|
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
|
||||||
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
|
if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
|
||||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||||
if match_def_path(cx, method_def_id, &paths::STR_LEN);
|
if match_def_path(cx, method_def_id, &paths::STR_LEN);
|
||||||
then {
|
then {
|
||||||
|
@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
|
fn lint_map_unit_fn(
|
||||||
let var_arg = &map_args[0];
|
cx: &LateContext<'_>,
|
||||||
|
stmt: &hir::Stmt<'_>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
|
||||||
|
) {
|
||||||
|
let var_arg = &map_args.0;
|
||||||
|
|
||||||
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
|
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
|
||||||
("Option", "Some", OPTION_MAP_UNIT_FN)
|
("Option", "Some", OPTION_MAP_UNIT_FN)
|
||||||
@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
|
|||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let fn_arg = &map_args[1];
|
let fn_arg = &map_args.1[0];
|
||||||
|
|
||||||
if is_unit_function(cx, fn_arg) {
|
if is_unit_function(cx, fn_arg) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||||
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
|
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
|
||||||
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
|
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
|
||||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
|
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
|
||||||
|
@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> {
|
|||||||
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
||||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||||
match ex.kind {
|
match ex.kind {
|
||||||
ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
|
ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
|
||||||
_ => walk_expr(self, ex),
|
_ => walk_expr(self, ex),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>(
|
|||||||
// check that `while_let_on_iterator` lint does not trigger
|
// check that `while_let_on_iterator` lint does not trigger
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if keyword == "while";
|
if keyword == "while";
|
||||||
if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
|
if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
|
||||||
if method_path.ident.name == sym::next;
|
if method_path.ident.name == sym::next;
|
||||||
if is_trait_method(cx, let_expr, sym::Iterator);
|
if is_trait_method(cx, let_expr, sym::Iterator);
|
||||||
then {
|
then {
|
||||||
|
@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
|||||||
self.is_chain_end = false;
|
self.is_chain_end = false;
|
||||||
|
|
||||||
match ex.kind {
|
match ex.kind {
|
||||||
ExprKind::MethodCall(_, [ref expr, ..], _) => {
|
ExprKind::MethodCall(_, expr, ..) => {
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
ExprKind::Binary(_, left, right) => {
|
ExprKind::Binary(_, left, right) => {
|
||||||
@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
|||||||
ExprKind::Index(..) |
|
ExprKind::Index(..) |
|
||||||
ExprKind::Ret(..) |
|
ExprKind::Ret(..) |
|
||||||
ExprKind::Repeat(..) |
|
ExprKind::Repeat(..) |
|
||||||
ExprKind::Yield(..) |
|
ExprKind::Yield(..) => walk_expr(self, ex),
|
||||||
ExprKind::MethodCall(..) => walk_expr(self, ex),
|
|
||||||
ExprKind::AddrOf(_, _, _) |
|
ExprKind::AddrOf(_, _, _) |
|
||||||
ExprKind::Block(_, _) |
|
ExprKind::Block(_, _) |
|
||||||
ExprKind::Break(_, _) |
|
ExprKind::Break(_, _) |
|
||||||
|
@ -42,11 +42,11 @@ pub(super) fn check<'tcx>(
|
|||||||
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
|
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
|
||||||
if !is_local_used(cx, needle, arg_id);
|
if !is_local_used(cx, needle, arg_id);
|
||||||
then {
|
then {
|
||||||
let haystack = if let ExprKind::MethodCall(path, args, _) =
|
let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
|
||||||
filter_recv.kind {
|
filter_recv.kind {
|
||||||
let p = path.ident.name;
|
let p = path.ident.name;
|
||||||
if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
|
if p == sym::iter || p == sym!(iter_mut) {
|
||||||
&args[0]
|
receiver
|
||||||
} else {
|
} else {
|
||||||
filter_recv
|
filter_recv
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ pub(super) fn check(
|
|||||||
if Some(id) == cx.tcx.lang_items().option_some_variant();
|
if Some(id) == cx.tcx.lang_items().option_some_variant();
|
||||||
then {
|
then {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
|
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
|
||||||
|
|
||||||
if *self_ty.kind() != ty::Str {
|
if *self_ty.kind() != ty::Str {
|
||||||
return false;
|
return false;
|
||||||
@ -37,7 +37,7 @@ pub(super) fn check(
|
|||||||
"like this",
|
"like this",
|
||||||
format!("{}{}.{}({})",
|
format!("{}{}.{}({})",
|
||||||
if info.eq { "" } else { "!" },
|
if info.eq { "" } else { "!" },
|
||||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||||
suggest,
|
suggest,
|
||||||
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
|
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
|
||||||
applicability,
|
applicability,
|
||||||
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
|
|||||||
"like this",
|
"like this",
|
||||||
format!("{}{}.{}('{}')",
|
format!("{}{}.{}('{}')",
|
||||||
if info.eq { "" } else { "!" },
|
if info.eq { "" } else { "!" },
|
||||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||||
suggest,
|
suggest,
|
||||||
c.escape_default()),
|
c.escape_default()),
|
||||||
applicability,
|
applicability,
|
||||||
|
@ -14,11 +14,14 @@ use super::CLONE_ON_COPY;
|
|||||||
|
|
||||||
/// Checks for the `CLONE_ON_COPY` lint.
|
/// Checks for the `CLONE_ON_COPY` lint.
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
|
pub(super) fn check(
|
||||||
let arg = match args {
|
cx: &LateContext<'_>,
|
||||||
[arg] if method_name == sym::clone => arg,
|
expr: &Expr<'_>,
|
||||||
_ => return,
|
method_name: Symbol,
|
||||||
};
|
receiver: &Expr<'_>,
|
||||||
|
args: &[Expr<'_>],
|
||||||
|
) {
|
||||||
|
let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
|
||||||
if cx
|
if cx
|
||||||
.typeck_results()
|
.typeck_results()
|
||||||
.type_dependent_def_id(expr.hir_id)
|
.type_dependent_def_id(expr.hir_id)
|
||||||
@ -81,7 +84,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
|
|||||||
// &*x is a nop, &x.clone() is not
|
// &*x is a nop, &x.clone() is not
|
||||||
ExprKind::AddrOf(..) => return,
|
ExprKind::AddrOf(..) => return,
|
||||||
// (*x).func() is useless, x.clone().func() can work in case func borrows self
|
// (*x).func() is useless, x.clone().func() can work in case func borrows self
|
||||||
ExprKind::MethodCall(_, [self_arg, ..], _)
|
ExprKind::MethodCall(_, self_arg, ..)
|
||||||
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
|
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -91,7 +94,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
|
|||||||
hir_callee.kind,
|
hir_callee.kind,
|
||||||
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
|
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
|
||||||
),
|
),
|
||||||
ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
|
ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
|
||||||
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
|
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
|
||||||
| ExprKind::Field(..)
|
| ExprKind::Field(..)
|
||||||
| ExprKind::Index(..) => true,
|
| ExprKind::Index(..) => true,
|
||||||
|
@ -10,12 +10,17 @@ use rustc_span::symbol::{sym, Symbol};
|
|||||||
|
|
||||||
use super::CLONE_ON_REF_PTR;
|
use super::CLONE_ON_REF_PTR;
|
||||||
|
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(
|
||||||
if !(args.len() == 1 && method_name == sym::clone) {
|
cx: &LateContext<'_>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
method_name: Symbol,
|
||||||
|
receiver: &hir::Expr<'_>,
|
||||||
|
args: &[hir::Expr<'_>],
|
||||||
|
) {
|
||||||
|
if !(args.is_empty() && method_name == sym::clone) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let arg = &args[0];
|
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||||
let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
|
|
||||||
|
|
||||||
if let ty::Adt(_, subst) = obj_ty.kind() {
|
if let ty::Adt(_, subst) = obj_ty.kind() {
|
||||||
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
|
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
|
||||||
@ -28,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
|
let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
|
||||||
|
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
|
@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
|
|||||||
// If the parent node's `to` argument is the same as the `to` argument
|
// If the parent node's `to` argument is the same as the `to` argument
|
||||||
// of the last replace call in the current chain, don't lint as it was already linted
|
// of the last replace call in the current chain, don't lint as it was already linted
|
||||||
if let Some(parent) = get_parent_expr(cx, expr)
|
if let Some(parent) = get_parent_expr(cx, expr)
|
||||||
&& let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
|
&& let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
|
||||||
&& eq_expr_value(cx, to, current_to)
|
&& eq_expr_value(cx, to, current_to)
|
||||||
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
|
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
|
||||||
{
|
{
|
||||||
@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
|
|||||||
let mut from_args = VecDeque::new();
|
let mut from_args = VecDeque::new();
|
||||||
|
|
||||||
let _: Option<()> = for_each_expr(expr, |e| {
|
let _: Option<()> = for_each_expr(expr, |e| {
|
||||||
if let Some(("replace", [_, from, to], _)) = method_call(e) {
|
if let Some(("replace", _, [from, to], _)) = method_call(e) {
|
||||||
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
|
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
|
||||||
methods.push_front(e);
|
methods.push_front(e);
|
||||||
from_args.push_front(from);
|
from_args.push_front(from);
|
||||||
@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
|
|||||||
.collect();
|
.collect();
|
||||||
let app = Applicability::MachineApplicable;
|
let app = Applicability::MachineApplicable;
|
||||||
let earliest_replace_call = replace_methods.methods.front().unwrap();
|
let earliest_replace_call = replace_methods.methods.front().unwrap();
|
||||||
if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
|
if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
COLLAPSIBLE_STR_REPLACE,
|
COLLAPSIBLE_STR_REPLACE,
|
||||||
|
@ -19,6 +19,7 @@ pub(super) fn check<'tcx>(
|
|||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
method_span: Span,
|
method_span: Span,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
receiver: &'tcx hir::Expr<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
) {
|
) {
|
||||||
// Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
|
// Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
|
||||||
@ -28,16 +29,13 @@ pub(super) fn check<'tcx>(
|
|||||||
loop {
|
loop {
|
||||||
arg_root = match &arg_root.kind {
|
arg_root = match &arg_root.kind {
|
||||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
|
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
|
||||||
hir::ExprKind::MethodCall(method_name, call_args, _) => {
|
hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
|
||||||
if call_args.len() == 1
|
if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
|
||||||
&& (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
|
let arg_type = cx.typeck_results().expr_ty(receiver);
|
||||||
&& {
|
|
||||||
let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
|
|
||||||
let base_type = arg_type.peel_refs();
|
let base_type = arg_type.peel_refs();
|
||||||
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
|
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
|
||||||
}
|
} {
|
||||||
{
|
receiver
|
||||||
&call_args[0]
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -114,11 +112,11 @@ pub(super) fn check<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
|
if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
|
||||||
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
|
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
|
||||||
"||"
|
"||"
|
||||||
} else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
|
} else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
|
||||||
@ -127,7 +125,7 @@ pub(super) fn check<'tcx>(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let arg_root = get_arg_root(cx, &args[1]);
|
let arg_root = get_arg_root(cx, &args[0]);
|
||||||
|
|
||||||
let span_replace_word = method_span.with_hi(expr.span.hi());
|
let span_replace_word = method_span.with_hi(expr.span.hi());
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
|||||||
if_chain! {
|
if_chain! {
|
||||||
if is_type_diagnostic_item(cx, ty, sym::Vec);
|
if is_type_diagnostic_item(cx, ty, sym::Vec);
|
||||||
//check source object
|
//check source object
|
||||||
if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
|
if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
|
||||||
if src_method.ident.as_str() == "drain";
|
if src_method.ident.as_str() == "drain";
|
||||||
let src_ty = cx.typeck_results().expr_ty(drain_vec);
|
let src_ty = cx.typeck_results().expr_ty(drain_vec);
|
||||||
//check if actual src type is mutable for code suggestion
|
//check if actual src type is mutable for code suggestion
|
||||||
|
@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
|
|||||||
let closure_expr = peel_blocks(&body.value);
|
let closure_expr = peel_blocks(&body.value);
|
||||||
let arg_id = body.params[0].pat.hir_id;
|
let arg_id = body.params[0].pat.hir_id;
|
||||||
match closure_expr.kind {
|
match closure_expr.kind {
|
||||||
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
|
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if ident.name == method_name;
|
if ident.name == method_name;
|
||||||
if let hir::ExprKind::Path(path) = &args[0].kind;
|
if let hir::ExprKind::Path(path) = &receiver.kind;
|
||||||
if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
|
if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
|
||||||
then {
|
then {
|
||||||
return arg_id == *local
|
return arg_id == *local
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
|
|||||||
};
|
};
|
||||||
// closure ends with is_some() or is_ok()
|
// closure ends with is_some() or is_ok()
|
||||||
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
|
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
|
||||||
if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
|
if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
|
||||||
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
|
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
|
||||||
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
|
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
|
||||||
Some(false)
|
Some(false)
|
||||||
@ -123,13 +123,13 @@ pub(super) fn check<'tcx>(
|
|||||||
if let [map_param] = map_body.params;
|
if let [map_param] = map_body.params;
|
||||||
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
|
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
|
||||||
// closure ends with expect() or unwrap()
|
// closure ends with expect() or unwrap()
|
||||||
if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
|
if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
|
||||||
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
|
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
|
||||||
|
|
||||||
// .filter(..).map(|y| f(y).copied().unwrap())
|
// .filter(..).map(|y| f(y).copied().unwrap())
|
||||||
// ~~~~
|
// ~~~~
|
||||||
let map_arg_peeled = match map_arg.kind {
|
let map_arg_peeled = match map_arg.kind {
|
||||||
ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
|
ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
|
||||||
original_arg
|
original_arg
|
||||||
},
|
},
|
||||||
_ => map_arg,
|
_ => map_arg,
|
||||||
|
@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
|||||||
) = arg.kind
|
) = arg.kind
|
||||||
|
|
||||||
// LHS of subtraction is "x.len()"
|
// LHS of subtraction is "x.len()"
|
||||||
&& let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
|
&& let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
|
||||||
&& lhs_path.ident.name == sym::len
|
&& lhs_path.ident.name == sym::len
|
||||||
|
|
||||||
// RHS of subtraction is 1
|
// RHS of subtraction is 1
|
||||||
|
@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol};
|
|||||||
use super::INEFFICIENT_TO_STRING;
|
use super::INEFFICIENT_TO_STRING;
|
||||||
|
|
||||||
/// Checks for the `INEFFICIENT_TO_STRING` lint
|
/// Checks for the `INEFFICIENT_TO_STRING` lint
|
||||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
pub fn check<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
method_name: Symbol,
|
||||||
|
receiver: &hir::Expr<'_>,
|
||||||
|
args: &[hir::Expr<'_>],
|
||||||
|
) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if args.len() == 1 && method_name == sym::to_string;
|
if args.is_empty() && method_name == sym::to_string;
|
||||||
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||||
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
|
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
|
||||||
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
|
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
|
||||||
let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
|
||||||
let self_ty = substs.type_at(0);
|
let self_ty = substs.type_at(0);
|
||||||
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
|
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
|
||||||
if deref_count >= 1;
|
if deref_count >= 1;
|
||||||
@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
|
|||||||
self_ty, deref_self_ty
|
self_ty, deref_self_ty
|
||||||
));
|
));
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
|
let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
expr.span,
|
expr.span,
|
||||||
"try dereferencing the receiver",
|
"try dereferencing the receiver",
|
||||||
|
@ -16,9 +16,9 @@ pub(super) fn check(
|
|||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
method_span: Span,
|
method_span: Span,
|
||||||
method_name: Symbol,
|
method_name: Symbol,
|
||||||
args: &[hir::Expr<'_>],
|
receiver: &hir::Expr<'_>,
|
||||||
) {
|
) {
|
||||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ty::Ref(..) = self_ty.kind();
|
if let ty::Ref(..) = self_ty.kind();
|
||||||
if method_name == sym::into_iter;
|
if method_name == sym::into_iter;
|
||||||
|
@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -
|
|||||||
&& range.end.map_or(true, |e| {
|
&& range.end.map_or(true, |e| {
|
||||||
if range.limits == RangeLimits::HalfOpen
|
if range.limits == RangeLimits::HalfOpen
|
||||||
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
|
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
|
||||||
&& let ExprKind::MethodCall(name, [self_arg], _) = e.kind
|
&& let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
|
||||||
&& name.ident.name == sym::len
|
&& name.ident.name == sym::len
|
||||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
|
&& let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
|
hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
|
||||||
if ident_eq(name, obj) && method.ident.name == sym::clone;
|
if ident_eq(name, obj) && method.ident.name == sym::clone;
|
||||||
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
|
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
|
||||||
if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
|
if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
|
||||||
|
@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/// Extracts a method call name, args, and `Span` of the method name.
|
/// Extracts a method call name, args, and `Span` of the method name.
|
||||||
fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
|
fn method_call<'tcx>(
|
||||||
if let ExprKind::MethodCall(path, args, _) = recv.kind {
|
recv: &'tcx hir::Expr<'tcx>,
|
||||||
if !args.iter().any(|e| e.span.from_expansion()) {
|
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
|
||||||
|
if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
|
||||||
|
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
|
||||||
let name = path.ident.name.as_str();
|
let name = path.ident.name.as_str();
|
||||||
return Some((name, args, path.ident.span));
|
return Some((name, receiver, args, path.ident.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||||||
hir::ExprKind::Call(func, args) => {
|
hir::ExprKind::Call(func, args) => {
|
||||||
from_iter_instead_of_collect::check(cx, expr, args, func);
|
from_iter_instead_of_collect::check(cx, expr, args, func);
|
||||||
},
|
},
|
||||||
hir::ExprKind::MethodCall(method_call, args, _) => {
|
hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
|
||||||
let method_span = method_call.ident.span;
|
let method_span = method_call.ident.span;
|
||||||
or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
|
or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
|
||||||
expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
|
expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
|
||||||
clone_on_copy::check(cx, expr, method_call.ident.name, args);
|
clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
|
||||||
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
|
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
|
||||||
inefficient_to_string::check(cx, expr, method_call.ident.name, args);
|
inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
|
||||||
single_char_add_str::check(cx, expr, args);
|
single_char_add_str::check(cx, expr, receiver, args);
|
||||||
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
|
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
|
||||||
single_char_pattern::check(cx, expr, method_call.ident.name, args);
|
single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
|
||||||
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
|
unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
|
||||||
},
|
},
|
||||||
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
|
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
|
||||||
let mut info = BinaryExprInfo {
|
let mut info = BinaryExprInfo {
|
||||||
@ -3379,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||||||
impl Methods {
|
impl Methods {
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
|
if let Some((name, recv, args, span)) = method_call(expr) {
|
||||||
match (name, args) {
|
match (name, args) {
|
||||||
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
|
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
|
||||||
zst_offset::check(cx, expr, recv);
|
zst_offset::check(cx, expr, recv);
|
||||||
@ -3399,13 +3401,13 @@ impl Methods {
|
|||||||
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
|
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
|
||||||
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
|
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
|
||||||
("collect", []) => match method_call(recv) {
|
("collect", []) => match method_call(recv) {
|
||||||
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
|
Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
|
||||||
iter_cloned_collect::check(cx, name, expr, recv2);
|
iter_cloned_collect::check(cx, name, expr, recv2);
|
||||||
},
|
},
|
||||||
Some(("map", [m_recv, m_arg], _)) => {
|
Some(("map", m_recv, [m_arg], _)) => {
|
||||||
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
|
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
|
||||||
},
|
},
|
||||||
Some(("take", [take_self_arg, take_arg], _)) => {
|
Some(("take", take_self_arg, [take_arg], _)) => {
|
||||||
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
|
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
|
||||||
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
|
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
|
||||||
}
|
}
|
||||||
@ -3413,26 +3415,26 @@ impl Methods {
|
|||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
|
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
|
||||||
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
|
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
|
||||||
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
|
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
|
||||||
iter_count::check(cx, expr, recv2, name2);
|
iter_count::check(cx, expr, recv2, name2);
|
||||||
},
|
},
|
||||||
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
|
Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
|
||||||
Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
|
Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
|
||||||
Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
|
Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
("drain", [arg]) => {
|
("drain", [arg]) => {
|
||||||
iter_with_drain::check(cx, expr, recv, span, arg);
|
iter_with_drain::check(cx, expr, recv, span, arg);
|
||||||
},
|
},
|
||||||
("ends_with", [arg]) => {
|
("ends_with", [arg]) => {
|
||||||
if let ExprKind::MethodCall(_, _, span) = expr.kind {
|
if let ExprKind::MethodCall(.., span) = expr.kind {
|
||||||
case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
|
case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
("expect", [_]) => match method_call(recv) {
|
("expect", [_]) => match method_call(recv) {
|
||||||
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
|
Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
|
||||||
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
|
Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
|
||||||
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
|
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
|
||||||
},
|
},
|
||||||
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
|
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
|
||||||
@ -3452,13 +3454,13 @@ impl Methods {
|
|||||||
flat_map_option::check(cx, expr, arg, span);
|
flat_map_option::check(cx, expr, arg, span);
|
||||||
},
|
},
|
||||||
("flatten", []) => match method_call(recv) {
|
("flatten", []) => match method_call(recv) {
|
||||||
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
|
Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
|
||||||
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
|
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
|
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
|
||||||
("for_each", [_]) => {
|
("for_each", [_]) => {
|
||||||
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
|
if let Some(("inspect", _, [_], span2)) = method_call(recv) {
|
||||||
inspect_for_each::check(cx, expr, span2);
|
inspect_for_each::check(cx, expr, span2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3478,12 +3480,12 @@ impl Methods {
|
|||||||
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
|
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
|
||||||
},
|
},
|
||||||
("join", [join_arg]) => {
|
("join", [join_arg]) => {
|
||||||
if let Some(("collect", _, span)) = method_call(recv) {
|
if let Some(("collect", _, _, span)) = method_call(recv) {
|
||||||
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
("last", []) | ("skip", [_]) => {
|
("last", []) | ("skip", [_]) => {
|
||||||
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
|
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
|
||||||
if let ("cloned", []) = (name2, args2) {
|
if let ("cloned", []) = (name2, args2) {
|
||||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||||
}
|
}
|
||||||
@ -3498,7 +3500,7 @@ impl Methods {
|
|||||||
} else {
|
} else {
|
||||||
map_err_ignore::check(cx, expr, m_arg);
|
map_err_ignore::check(cx, expr, m_arg);
|
||||||
}
|
}
|
||||||
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
|
if let Some((name, recv2, args, span2)) = method_call(recv) {
|
||||||
match (name, args) {
|
match (name, args) {
|
||||||
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
|
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
|
||||||
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
|
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
|
||||||
@ -3518,7 +3520,7 @@ impl Methods {
|
|||||||
manual_ok_or::check(cx, expr, recv, def, map);
|
manual_ok_or::check(cx, expr, recv, def, map);
|
||||||
},
|
},
|
||||||
("next", []) => {
|
("next", []) => {
|
||||||
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
|
if let Some((name2, recv2, args2, _)) = method_call(recv) {
|
||||||
match (name2, args2) {
|
match (name2, args2) {
|
||||||
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||||
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
|
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
|
||||||
@ -3531,10 +3533,10 @@ impl Methods {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
("nth", [n_arg]) => match method_call(recv) {
|
("nth", [n_arg]) => match method_call(recv) {
|
||||||
Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
||||||
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||||
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
|
Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
|
||||||
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
|
Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
|
||||||
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
|
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
|
||||||
},
|
},
|
||||||
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
|
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
|
||||||
@ -3591,7 +3593,7 @@ impl Methods {
|
|||||||
},
|
},
|
||||||
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
|
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
|
||||||
("take", [_arg]) => {
|
("take", [_arg]) => {
|
||||||
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
|
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
|
||||||
if let ("cloned", []) = (name2, args2) {
|
if let ("cloned", []) = (name2, args2) {
|
||||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||||
}
|
}
|
||||||
@ -3614,13 +3616,13 @@ impl Methods {
|
|||||||
},
|
},
|
||||||
("unwrap", []) => {
|
("unwrap", []) => {
|
||||||
match method_call(recv) {
|
match method_call(recv) {
|
||||||
Some(("get", [recv, get_arg], _)) => {
|
Some(("get", recv, [get_arg], _)) => {
|
||||||
get_unwrap::check(cx, expr, recv, get_arg, false);
|
get_unwrap::check(cx, expr, recv, get_arg, false);
|
||||||
},
|
},
|
||||||
Some(("get_mut", [recv, get_arg], _)) => {
|
Some(("get_mut", recv, [get_arg], _)) => {
|
||||||
get_unwrap::check(cx, expr, recv, get_arg, true);
|
get_unwrap::check(cx, expr, recv, get_arg, true);
|
||||||
},
|
},
|
||||||
Some(("or", [recv, or_arg], or_span)) => {
|
Some(("or", recv, [or_arg], or_span)) => {
|
||||||
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
|
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -3629,19 +3631,19 @@ impl Methods {
|
|||||||
},
|
},
|
||||||
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
|
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
|
||||||
("unwrap_or", [u_arg]) => match method_call(recv) {
|
("unwrap_or", [u_arg]) => match method_call(recv) {
|
||||||
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
|
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
|
||||||
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
|
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
|
||||||
},
|
},
|
||||||
Some(("map", [m_recv, m_arg], span)) => {
|
Some(("map", m_recv, [m_arg], span)) => {
|
||||||
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
|
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
|
||||||
},
|
},
|
||||||
Some(("then_some", [t_recv, t_arg], _)) => {
|
Some(("then_some", t_recv, [t_arg], _)) => {
|
||||||
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
|
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
("unwrap_or_else", [u_arg]) => match method_call(recv) {
|
("unwrap_or_else", [u_arg]) => match method_call(recv) {
|
||||||
Some(("map", [recv, map_arg], _))
|
Some(("map", recv, [map_arg], _))
|
||||||
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
|
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
|
||||||
_ => {
|
_ => {
|
||||||
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
||||||
@ -3649,7 +3651,7 @@ impl Methods {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
("zip", [arg]) => {
|
("zip", [arg]) => {
|
||||||
if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
|
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
|
||||||
&& name.ident.name == sym::iter
|
&& name.ident.name == sym::iter
|
||||||
{
|
{
|
||||||
range_zip_with_len::check(cx, expr, iter_recv, arg);
|
range_zip_with_len::check(cx, expr, iter_recv, arg);
|
||||||
@ -3662,7 +3664,7 @@ impl Methods {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
|
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
|
||||||
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
|
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
|
||||||
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
|
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,12 @@ enum OpenOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
|
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
|
||||||
if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
|
if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
|
||||||
let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
|
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||||
|
|
||||||
// Only proceed if this is a call on some object of type std::fs::OpenOptions
|
// Only proceed if this is a call on some object of type std::fs::OpenOptions
|
||||||
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
|
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
|
||||||
let argument_option = match arguments[1].kind {
|
let argument_option = match arguments[0].kind {
|
||||||
ExprKind::Lit(ref span) => {
|
ExprKind::Lit(ref span) => {
|
||||||
if let Spanned {
|
if let Spanned {
|
||||||
node: LitKind::Bool(lit),
|
node: LitKind::Bool(lit),
|
||||||
@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
get_open_options(cx, &arguments[0], options);
|
get_open_options(cx, receiver, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,12 @@ pub(super) fn check<'tcx>(
|
|||||||
let closure_expr = peel_blocks(&closure_body.value);
|
let closure_expr = peel_blocks(&closure_body.value);
|
||||||
|
|
||||||
match &closure_expr.kind {
|
match &closure_expr.kind {
|
||||||
hir::ExprKind::MethodCall(_, args, _) => {
|
hir::ExprKind::MethodCall(_, receiver, [], _) => {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if args.len() == 1;
|
if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
|
||||||
if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
|
|
||||||
let adj = cx
|
let adj = cx
|
||||||
.typeck_results()
|
.typeck_results()
|
||||||
.expr_adjustments(&args[0])
|
.expr_adjustments(receiver)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| &x.kind)
|
.map(|x| &x.kind)
|
||||||
.collect::<Box<[_]>>();
|
.collect::<Box<[_]>>();
|
||||||
|
@ -20,6 +20,7 @@ pub(super) fn check<'tcx>(
|
|||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
method_span: Span,
|
method_span: Span,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
receiver: &'tcx hir::Expr<'_>,
|
||||||
args: &'tcx [hir::Expr<'_>],
|
args: &'tcx [hir::Expr<'_>],
|
||||||
) {
|
) {
|
||||||
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
|
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
|
||||||
@ -144,7 +145,7 @@ pub(super) fn check<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let [self_arg, arg] = args {
|
if let [arg] = args {
|
||||||
let inner_arg = if let hir::ExprKind::Block(
|
let inner_arg = if let hir::ExprKind::Block(
|
||||||
hir::Block {
|
hir::Block {
|
||||||
stmts: [],
|
stmts: [],
|
||||||
@ -163,11 +164,11 @@ pub(super) fn check<'tcx>(
|
|||||||
let or_has_args = !or_args.is_empty();
|
let or_has_args = !or_args.is_empty();
|
||||||
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
|
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
|
||||||
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
||||||
check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
|
check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||||
check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
|
check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
|
|||||||
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
|
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
|
||||||
if is_integer_const(cx, start, 0);
|
if is_integer_const(cx, start, 0);
|
||||||
// `.len()` call
|
// `.len()` call
|
||||||
if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
|
if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
|
||||||
if len_path.ident.name == sym::len;
|
if len_path.ident.name == sym::len;
|
||||||
// `.iter()` and `.len()` called on same `Path`
|
// `.iter()` and `.len()` called on same `Path`
|
||||||
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
|
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
|
||||||
|
@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths};
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
|
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||||
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||||
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
||||||
single_char_push_string::check(cx, expr, args);
|
single_char_push_string::check(cx, expr, receiver, args);
|
||||||
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
|
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
|
||||||
single_char_insert_string::check(cx, expr, args);
|
single_char_insert_string::check(cx, expr, receiver, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ use rustc_lint::LateContext;
|
|||||||
use super::SINGLE_CHAR_ADD_STR;
|
use super::SINGLE_CHAR_ADD_STR;
|
||||||
|
|
||||||
/// lint for length-1 `str`s as argument for `insert_str`
|
/// lint for length-1 `str`s as argument for `insert_str`
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
|
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
|
||||||
let base_string_snippet =
|
let base_string_snippet =
|
||||||
snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
|
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
|
||||||
let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
|
let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
|
||||||
let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
|
let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
|
@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol;
|
|||||||
use super::SINGLE_CHAR_PATTERN;
|
use super::SINGLE_CHAR_PATTERN;
|
||||||
|
|
||||||
const PATTERN_METHODS: [(&str, usize); 24] = [
|
const PATTERN_METHODS: [(&str, usize); 24] = [
|
||||||
("contains", 1),
|
("contains", 0),
|
||||||
("starts_with", 1),
|
("starts_with", 0),
|
||||||
("ends_with", 1),
|
("ends_with", 0),
|
||||||
("find", 1),
|
("find", 0),
|
||||||
("rfind", 1),
|
("rfind", 0),
|
||||||
("split", 1),
|
("split", 0),
|
||||||
("split_inclusive", 1),
|
("split_inclusive", 0),
|
||||||
("rsplit", 1),
|
("rsplit", 0),
|
||||||
("split_terminator", 1),
|
("split_terminator", 0),
|
||||||
("rsplit_terminator", 1),
|
("rsplit_terminator", 0),
|
||||||
("splitn", 2),
|
("splitn", 1),
|
||||||
("rsplitn", 2),
|
("rsplitn", 1),
|
||||||
("split_once", 1),
|
("split_once", 0),
|
||||||
("rsplit_once", 1),
|
("rsplit_once", 0),
|
||||||
("matches", 1),
|
("matches", 0),
|
||||||
("rmatches", 1),
|
("rmatches", 0),
|
||||||
("match_indices", 1),
|
("match_indices", 0),
|
||||||
("rmatch_indices", 1),
|
("rmatch_indices", 0),
|
||||||
("strip_prefix", 1),
|
("strip_prefix", 0),
|
||||||
("strip_suffix", 1),
|
("strip_suffix", 0),
|
||||||
("trim_start_matches", 1),
|
("trim_start_matches", 0),
|
||||||
("trim_end_matches", 1),
|
("trim_end_matches", 0),
|
||||||
("replace", 1),
|
("replace", 0),
|
||||||
("replacen", 1),
|
("replacen", 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
|
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
|
||||||
pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
_expr: &hir::Expr<'_>,
|
||||||
|
method_name: Symbol,
|
||||||
|
receiver: &hir::Expr<'_>,
|
||||||
|
args: &[hir::Expr<'_>],
|
||||||
|
) {
|
||||||
for &(method, pos) in &PATTERN_METHODS {
|
for &(method, pos) in &PATTERN_METHODS {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
|
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
|
||||||
if *ty.kind() == ty::Str;
|
if *ty.kind() == ty::Str;
|
||||||
if method_name.as_str() == method && args.len() > pos;
|
if method_name.as_str() == method && args.len() > pos;
|
||||||
let arg = &args[pos];
|
let arg = &args[pos];
|
||||||
|
@ -8,11 +8,11 @@ use rustc_lint::LateContext;
|
|||||||
use super::SINGLE_CHAR_ADD_STR;
|
use super::SINGLE_CHAR_ADD_STR;
|
||||||
|
|
||||||
/// lint for length-1 `str`s as argument for `push_str`
|
/// lint for length-1 `str`s as argument for `push_str`
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
|
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
|
||||||
let base_string_snippet =
|
let base_string_snippet =
|
||||||
snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
|
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
|
||||||
let sugg = format!("{}.push({})", base_string_snippet, extension_string);
|
let sugg = format!("{}.push({})", base_string_snippet, extension_string);
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
|
@ -292,7 +292,7 @@ fn parse_iter_usage<'tcx>(
|
|||||||
) -> Option<IterUsage> {
|
) -> Option<IterUsage> {
|
||||||
let (kind, span) = match iter.next() {
|
let (kind, span) = match iter.next() {
|
||||||
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
|
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
|
||||||
let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
|
let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
|
||||||
(name, args)
|
(name, args)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -327,7 +327,7 @@ fn parse_iter_usage<'tcx>(
|
|||||||
} else {
|
} else {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Some((_, Node::Expr(next_expr))) = iter.next();
|
if let Some((_, Node::Expr(next_expr))) = iter.next();
|
||||||
if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
|
if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
|
||||||
if next_name.ident.name == sym::next;
|
if next_name.ident.name == sym::next;
|
||||||
if next_expr.span.ctxt() == ctxt;
|
if next_expr.span.ctxt() == ctxt;
|
||||||
if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
|
if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
|
||||||
@ -367,7 +367,7 @@ fn parse_iter_usage<'tcx>(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ if e.span.ctxt() != ctxt => (None, span),
|
_ if e.span.ctxt() != ctxt => (None, span),
|
||||||
ExprKind::MethodCall(name, [_], _)
|
ExprKind::MethodCall(name, _, [], _)
|
||||||
if name.ident.name == sym::unwrap
|
if name.ident.name == sym::unwrap
|
||||||
&& cx
|
&& cx
|
||||||
.typeck_results()
|
.typeck_results()
|
||||||
|
@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
|
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
|
||||||
let target = &arglists[0][0];
|
let target = &arglists[0].0;
|
||||||
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||||
let ref_str = if *self_ty.kind() == ty::Str {
|
let ref_str = if *self_ty.kind() == ty::Str {
|
||||||
""
|
""
|
||||||
|
@ -43,7 +43,7 @@ pub fn check_for_loop_iter(
|
|||||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||||
then {
|
then {
|
||||||
let snippet = if_chain! {
|
let snippet = if_chain! {
|
||||||
if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
|
if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
|
||||||
if maybe_iter_method_name.ident.name == sym::iter;
|
if maybe_iter_method_name.ident.name == sym::iter;
|
||||||
|
|
||||||
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||||
|
@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
|
|||||||
// This is a duplicate of what's happening in clippy_lints::methods::method_call,
|
// This is a duplicate of what's happening in clippy_lints::methods::method_call,
|
||||||
// which isn't ideal, We want to get the method call span,
|
// which isn't ideal, We want to get the method call span,
|
||||||
// but prefer to avoid changing the signature of the function itself.
|
// but prefer to avoid changing the signature of the function itself.
|
||||||
if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
|
if let hir::ExprKind::MethodCall(.., span) = expr.kind {
|
||||||
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
|
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
span,
|
span,
|
||||||
|
@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
|
|||||||
// The two exprs are method calls.
|
// The two exprs are method calls.
|
||||||
// Check to see that the function is the same and the arguments are mirrored
|
// Check to see that the function is the same and the arguments are mirrored
|
||||||
// This is enough because the receiver of the method is listed in the arguments
|
// This is enough because the receiver of the method is listed in the arguments
|
||||||
(ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
|
(
|
||||||
|
ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
|
||||||
|
ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
|
||||||
|
) => {
|
||||||
left_segment.ident == right_segment.ident
|
left_segment.ident == right_segment.ident
|
||||||
&& iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
|
&& iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
|
||||||
|
&& mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
|
||||||
},
|
},
|
||||||
// Two tuples with mirrored contents
|
// Two tuples with mirrored contents
|
||||||
(ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
|
(ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
|
||||||
@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
|
|||||||
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
|
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
|
||||||
Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
|
Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
|
||||||
] = &closure_body.params;
|
] = &closure_body.params;
|
||||||
if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
|
if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
|
||||||
if method_path.ident.name == sym::cmp;
|
if method_path.ident.name == sym::cmp;
|
||||||
if is_trait_method(cx, &closure_body.value, sym::Ord);
|
if is_trait_method(cx, &closure_body.value, sym::Ord);
|
||||||
then {
|
then {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user