2022-09-04 19:46:35 +00:00
|
|
|
use crate::lints::{
|
|
|
|
PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
|
2022-10-29 13:14:02 +00:00
|
|
|
UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim,
|
2023-06-11 15:44:28 +00:00
|
|
|
UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
|
|
|
|
UnusedResult,
|
2022-09-04 19:46:35 +00:00
|
|
|
};
|
2020-03-27 20:54:52 +00:00
|
|
|
use crate::Lint;
|
2020-01-09 06:52:01 +00:00
|
|
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
2020-04-27 17:56:11 +00:00
|
|
|
use rustc_ast as ast;
|
2021-07-30 22:12:11 +00:00
|
|
|
use rustc_ast::util::{classify, parser};
|
2020-04-27 17:56:11 +00:00
|
|
|
use rustc_ast::{ExprKind, StmtKind};
|
2022-09-04 19:46:35 +00:00
|
|
|
use rustc_errors::{pluralize, MultiSpan};
|
2020-01-05 01:37:57 +00:00
|
|
|
use rustc_hir as hir;
|
|
|
|
use rustc_hir::def::{DefKind, Res};
|
|
|
|
use rustc_hir::def_id::DefId;
|
2023-04-06 23:11:19 +00:00
|
|
|
use rustc_infer::traits::util::elaborate;
|
2020-03-29 15:19:48 +00:00
|
|
|
use rustc_middle::ty::adjustment;
|
2023-02-22 15:51:17 +00:00
|
|
|
use rustc_middle::ty::{self, Ty};
|
2020-01-01 18:30:57 +00:00
|
|
|
use rustc_span::symbol::Symbol;
|
|
|
|
use rustc_span::symbol::{kw, sym};
|
2022-08-07 10:36:54 +00:00
|
|
|
use rustc_span::{BytePos, Span};
|
2022-11-13 12:02:52 +00:00
|
|
|
use std::iter;
|
2015-09-15 22:58:19 +00:00
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_must_use` lint detects unused result of a type flagged as
|
|
|
|
/// `#[must_use]`.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// fn returns_result() -> Result<(), ()> {
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// returns_result();
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// The `#[must_use]` attribute is an indicator that it is a mistake to
|
|
|
|
/// ignore the value. See [the reference] for more details.
|
|
|
|
///
|
|
|
|
/// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
2015-09-15 22:58:19 +00:00
|
|
|
pub UNUSED_MUST_USE,
|
|
|
|
Warn,
|
2019-07-18 22:05:23 +00:00
|
|
|
"unused result of a type flagged as `#[must_use]`",
|
2019-10-08 22:47:08 +00:00
|
|
|
report_in_external_macro
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_results` lint checks for the unused result of an
|
|
|
|
/// expression in a statement.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust,compile_fail
|
|
|
|
/// #![deny(unused_results)]
|
|
|
|
/// fn foo<T>() -> T { panic!() }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// foo::<usize>();
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// Ignoring the return value of a function may indicate a mistake. In
|
|
|
|
/// cases were it is almost certain that the result should be used, it is
|
|
|
|
/// recommended to annotate the function with the [`must_use` attribute].
|
|
|
|
/// Failure to use such a return value will trigger the [`unused_must_use`
|
|
|
|
/// lint] which is warn-by-default. The `unused_results` lint is
|
|
|
|
/// essentially the same, but triggers for *all* return values.
|
|
|
|
///
|
|
|
|
/// This lint is "allow" by default because it can be noisy, and may not be
|
|
|
|
/// an actual problem. For example, calling the `remove` method of a `Vec`
|
|
|
|
/// or `HashMap` returns the previous value, which you may not care about.
|
|
|
|
/// Using this lint would require explicitly ignoring or discarding such
|
|
|
|
/// values.
|
|
|
|
///
|
|
|
|
/// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
|
|
|
/// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
|
2015-09-15 22:58:19 +00:00
|
|
|
pub UNUSED_RESULTS,
|
|
|
|
Allow,
|
|
|
|
"unused result of an expression in a statement"
|
|
|
|
}
|
|
|
|
|
2019-04-03 14:05:40 +00:00
|
|
|
declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
2023-06-11 15:44:28 +00:00
|
|
|
let hir::StmtKind::Semi(mut expr) = s.kind else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut expr_is_from_block = false;
|
|
|
|
while let hir::ExprKind::Block(blk, ..) = expr.kind
|
|
|
|
&& let hir::Block { expr: Some(e), .. } = blk
|
|
|
|
{
|
|
|
|
expr = e;
|
|
|
|
expr_is_from_block = true;
|
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2019-09-26 13:39:48 +00:00
|
|
|
if let hir::ExprKind::Ret(..) = expr.kind {
|
2015-09-15 22:58:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-16 14:56:42 +00:00
|
|
|
if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
|
|
|
|
&& let ty = cx.typeck_results().expr_ty(&await_expr)
|
2022-12-13 11:07:42 +00:00
|
|
|
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
|
2022-08-16 14:56:42 +00:00
|
|
|
&& cx.tcx.ty_is_opaque_future(ty)
|
2022-08-17 15:21:43 +00:00
|
|
|
&& let async_fn_def_id = cx.tcx.parent(*future_def_id)
|
2023-05-12 02:08:39 +00:00
|
|
|
&& matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn)
|
|
|
|
// Check that this `impl Future` actually comes from an `async fn`
|
|
|
|
&& cx.tcx.asyncness(async_fn_def_id).is_async()
|
2022-08-17 15:21:43 +00:00
|
|
|
&& check_must_use_def(
|
|
|
|
cx,
|
|
|
|
async_fn_def_id,
|
|
|
|
expr.span,
|
|
|
|
"output of future returned by ",
|
|
|
|
"",
|
2023-06-11 15:44:28 +00:00
|
|
|
expr_is_from_block,
|
2022-08-17 15:21:43 +00:00
|
|
|
)
|
2022-08-16 14:56:42 +00:00
|
|
|
{
|
|
|
|
// We have a bare `foo().await;` on an opaque type from an async function that was
|
|
|
|
// annotated with `#[must_use]`.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
let ty = cx.typeck_results().expr_ty(&expr);
|
2017-08-08 00:20:19 +00:00
|
|
|
|
2022-11-13 12:02:52 +00:00
|
|
|
let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
|
|
|
|
let type_lint_emitted_or_suppressed = match must_use_result {
|
|
|
|
Some(path) => {
|
2023-06-11 15:44:28 +00:00
|
|
|
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
|
2022-11-13 12:02:52 +00:00
|
|
|
true
|
2018-03-11 00:23:28 +00:00
|
|
|
}
|
2022-11-13 12:02:52 +00:00
|
|
|
None => false,
|
2018-03-11 00:23:28 +00:00
|
|
|
};
|
2022-11-13 12:02:52 +00:00
|
|
|
|
2023-06-11 15:44:28 +00:00
|
|
|
let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block);
|
2022-11-13 12:02:52 +00:00
|
|
|
|
|
|
|
if !fn_warned && type_lint_emitted_or_suppressed {
|
2018-10-08 20:08:01 +00:00
|
|
|
// We don't warn about unused unit or uninhabited types.
|
|
|
|
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
|
|
|
|
return;
|
2018-03-11 00:23:28 +00:00
|
|
|
}
|
2018-10-08 20:08:01 +00:00
|
|
|
|
2019-09-26 13:39:48 +00:00
|
|
|
let must_use_op = match expr.kind {
|
2018-03-11 00:23:28 +00:00
|
|
|
// Hardcoding operators here seemed more expedient than the
|
|
|
|
// refactoring that would be needed to look up the `#[must_use]`
|
|
|
|
// attribute which does exist on the comparison trait methods
|
2018-07-11 12:05:29 +00:00
|
|
|
hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
|
2018-07-12 00:20:31 +00:00
|
|
|
hir::BinOpKind::Eq
|
|
|
|
| hir::BinOpKind::Lt
|
|
|
|
| hir::BinOpKind::Le
|
|
|
|
| hir::BinOpKind::Ne
|
|
|
|
| hir::BinOpKind::Ge
|
|
|
|
| hir::BinOpKind::Gt => Some("comparison"),
|
|
|
|
hir::BinOpKind::Add
|
|
|
|
| hir::BinOpKind::Sub
|
|
|
|
| hir::BinOpKind::Div
|
|
|
|
| hir::BinOpKind::Mul
|
2018-03-11 00:23:28 +00:00
|
|
|
| hir::BinOpKind::Rem => Some("arithmetic operation"),
|
2018-07-11 10:44:53 +00:00
|
|
|
hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
|
2018-07-12 00:20:31 +00:00
|
|
|
hir::BinOpKind::BitXor
|
|
|
|
| hir::BinOpKind::BitAnd
|
|
|
|
| hir::BinOpKind::BitOr
|
|
|
|
| hir::BinOpKind::Shl
|
2018-03-11 00:23:28 +00:00
|
|
|
| hir::BinOpKind::Shr => Some("bitwise operation"),
|
|
|
|
},
|
2021-06-18 07:09:40 +00:00
|
|
|
hir::ExprKind::AddrOf(..) => Some("borrow"),
|
2018-07-11 12:05:29 +00:00
|
|
|
hir::ExprKind::Unary(..) => Some("unary operation"),
|
2018-03-11 00:23:28 +00:00
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2022-11-13 12:02:52 +00:00
|
|
|
let mut op_warned = false;
|
|
|
|
|
2018-03-11 00:23:28 +00:00
|
|
|
if let Some(must_use_op) = must_use_op {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
|
|
|
UNUSED_MUST_USE,
|
|
|
|
expr.span,
|
|
|
|
UnusedOp {
|
|
|
|
op: must_use_op,
|
|
|
|
label: expr.span,
|
2023-06-11 15:44:28 +00:00
|
|
|
suggestion: if expr_is_from_block {
|
|
|
|
UnusedOpSuggestion::BlockTailExpr {
|
|
|
|
before_span: expr.span.shrink_to_lo(),
|
|
|
|
after_span: expr.span.shrink_to_hi(),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() }
|
|
|
|
},
|
2022-09-04 19:46:35 +00:00
|
|
|
},
|
|
|
|
);
|
2018-03-11 00:23:28 +00:00
|
|
|
op_warned = true;
|
2017-08-08 00:20:19 +00:00
|
|
|
}
|
2018-03-11 00:23:28 +00:00
|
|
|
|
2022-11-13 12:02:52 +00:00
|
|
|
if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
2023-06-11 15:44:28 +00:00
|
|
|
fn check_fn_must_use(
|
|
|
|
cx: &LateContext<'_>,
|
|
|
|
expr: &hir::Expr<'_>,
|
|
|
|
expr_is_from_block: bool,
|
|
|
|
) -> bool {
|
2022-11-13 12:02:52 +00:00
|
|
|
let maybe_def_id = match expr.kind {
|
|
|
|
hir::ExprKind::Call(ref callee, _) => {
|
|
|
|
match callee.kind {
|
|
|
|
hir::ExprKind::Path(ref qpath) => {
|
|
|
|
match cx.qpath_res(qpath, callee.hir_id) {
|
|
|
|
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
|
|
|
|
// `Res::Local` if it was a closure, for which we
|
|
|
|
// do not currently support must-use linting
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::ExprKind::MethodCall(..) => {
|
|
|
|
cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
if let Some(def_id) = maybe_def_id {
|
2023-06-11 15:44:28 +00:00
|
|
|
check_must_use_def(
|
|
|
|
cx,
|
|
|
|
def_id,
|
|
|
|
expr.span,
|
|
|
|
"return value of ",
|
|
|
|
"",
|
|
|
|
expr_is_from_block,
|
|
|
|
)
|
2022-11-13 12:02:52 +00:00
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A path through a type to a must_use source. Contains useful info for the lint.
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum MustUsePath {
|
|
|
|
/// Suppress must_use checking.
|
|
|
|
Suppressed,
|
|
|
|
/// The root of the normal must_use lint with an optional message.
|
|
|
|
Def(Span, DefId, Option<Symbol>),
|
|
|
|
Boxed(Box<Self>),
|
|
|
|
Opaque(Box<Self>),
|
|
|
|
TraitObject(Box<Self>),
|
|
|
|
TupleElement(Vec<(usize, Self)>),
|
|
|
|
Array(Box<Self>, u64),
|
|
|
|
/// The root of the unused_closures lint.
|
|
|
|
Closure(Span),
|
|
|
|
/// The root of the unused_generators lint.
|
|
|
|
Generator(Span),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument(skip(cx, expr), level = "debug", ret)]
|
|
|
|
fn is_ty_must_use<'tcx>(
|
2020-06-25 20:41:36 +00:00
|
|
|
cx: &LateContext<'tcx>,
|
2019-05-27 19:11:15 +00:00
|
|
|
ty: Ty<'tcx>,
|
2019-11-30 14:08:22 +00:00
|
|
|
expr: &hir::Expr<'_>,
|
2019-05-23 21:56:23 +00:00
|
|
|
span: Span,
|
2022-11-13 12:02:52 +00:00
|
|
|
) -> Option<MustUsePath> {
|
2020-03-16 17:51:55 +00:00
|
|
|
if ty.is_unit()
|
2022-10-23 22:32:17 +00:00
|
|
|
|| !ty.is_inhabited_from(
|
|
|
|
cx.tcx,
|
2020-03-18 18:27:59 +00:00
|
|
|
cx.tcx.parent_module(expr.hir_id).to_def_id(),
|
2020-03-16 17:51:55 +00:00
|
|
|
cx.param_env,
|
|
|
|
)
|
2019-05-27 19:11:15 +00:00
|
|
|
{
|
2022-11-13 12:02:52 +00:00
|
|
|
return Some(MustUsePath::Suppressed);
|
2019-05-27 19:11:15 +00:00
|
|
|
}
|
|
|
|
|
2020-08-02 22:49:11 +00:00
|
|
|
match *ty.kind() {
|
2019-06-29 12:53:46 +00:00
|
|
|
ty::Adt(..) if ty.is_box() => {
|
|
|
|
let boxed_ty = ty.boxed_ty();
|
2022-11-13 12:02:52 +00:00
|
|
|
is_ty_must_use(cx, boxed_ty, expr, span)
|
|
|
|
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
|
2019-06-29 12:53:46 +00:00
|
|
|
}
|
2022-11-13 12:02:52 +00:00
|
|
|
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
|
2022-12-13 11:07:42 +00:00
|
|
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
2023-04-17 23:19:08 +00:00
|
|
|
elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied())
|
|
|
|
// We only care about self bounds for the impl-trait
|
|
|
|
.filter_only_self()
|
|
|
|
.find_map(|(pred, _span)| {
|
|
|
|
// We only look at the `DefId`, so it is safe to skip the binder here.
|
2023-06-19 20:46:46 +00:00
|
|
|
if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
|
|
|
|
pred.kind().skip_binder()
|
2023-04-17 23:19:08 +00:00
|
|
|
{
|
|
|
|
let def_id = poly_trait_predicate.trait_ref.def_id;
|
2022-11-13 12:02:52 +00:00
|
|
|
|
2023-04-17 23:19:08 +00:00
|
|
|
is_def_must_use(cx, def_id, span)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
|
2019-05-23 21:56:23 +00:00
|
|
|
}
|
2022-12-10 20:31:01 +00:00
|
|
|
ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
|
|
|
|
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
|
|
|
|
{
|
|
|
|
let def_id = trait_ref.def_id;
|
|
|
|
is_def_must_use(cx, def_id, span)
|
2022-12-27 17:53:29 +00:00
|
|
|
.map(|inner| MustUsePath::TraitObject(Box::new(inner)))
|
2022-12-10 20:31:01 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}),
|
2022-11-13 12:02:52 +00:00
|
|
|
ty::Tuple(tys) => {
|
|
|
|
let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
|
|
|
|
debug_assert_eq!(elem_exprs.len(), tys.len());
|
|
|
|
elem_exprs
|
2019-05-27 15:48:43 +00:00
|
|
|
} else {
|
2022-02-25 11:30:16 +00:00
|
|
|
&[]
|
2019-05-27 15:48:43 +00:00
|
|
|
};
|
2022-11-13 12:02:52 +00:00
|
|
|
|
|
|
|
// Default to `expr`.
|
|
|
|
let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
|
|
|
|
|
|
|
|
let nested_must_use = tys
|
|
|
|
.iter()
|
|
|
|
.zip(elem_exprs)
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(i, (ty, expr))| {
|
|
|
|
is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path))
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
if !nested_must_use.is_empty() {
|
|
|
|
Some(MustUsePath::TupleElement(nested_must_use))
|
|
|
|
} else {
|
|
|
|
None
|
2019-05-27 15:48:43 +00:00
|
|
|
}
|
2019-05-23 21:56:23 +00:00
|
|
|
}
|
2023-02-14 08:51:19 +00:00
|
|
|
ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) {
|
2020-10-22 18:42:44 +00:00
|
|
|
// If the array is empty we don't lint, to avoid false positives
|
2022-11-13 12:02:52 +00:00
|
|
|
Some(0) | None => None,
|
2019-06-29 15:23:15 +00:00
|
|
|
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
2022-11-13 12:02:52 +00:00
|
|
|
Some(len) => is_ty_must_use(cx, ty, expr, span)
|
|
|
|
.map(|inner| MustUsePath::Array(Box::new(inner), len)),
|
2019-06-29 15:23:15 +00:00
|
|
|
},
|
2022-11-13 12:02:52 +00:00
|
|
|
ty::Closure(..) => Some(MustUsePath::Closure(span)),
|
2022-11-18 21:56:22 +00:00
|
|
|
ty::Generator(def_id, ..) => {
|
|
|
|
// async fn should be treated as "implementor of `Future`"
|
2022-11-26 20:33:12 +00:00
|
|
|
let must_use = if cx.tcx.generator_is_async(def_id) {
|
2022-11-18 21:56:22 +00:00
|
|
|
let def_id = cx.tcx.lang_items().future_trait().unwrap();
|
|
|
|
is_def_must_use(cx, def_id, span)
|
|
|
|
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
must_use.or(Some(MustUsePath::Generator(span)))
|
|
|
|
}
|
2022-11-13 12:02:52 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
|
|
|
|
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
|
|
|
|
// check for #[must_use = "..."]
|
|
|
|
let reason = attr.value_str();
|
|
|
|
Some(MustUsePath::Def(span, def_id, reason))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns whether further errors should be suppressed because either a lint has been emitted or the type should be ignored.
|
|
|
|
fn check_must_use_def(
|
|
|
|
cx: &LateContext<'_>,
|
|
|
|
def_id: DefId,
|
|
|
|
span: Span,
|
|
|
|
descr_pre_path: &str,
|
|
|
|
descr_post_path: &str,
|
2023-06-11 15:44:28 +00:00
|
|
|
expr_is_from_block: bool,
|
2022-11-13 12:02:52 +00:00
|
|
|
) -> bool {
|
|
|
|
is_def_must_use(cx, def_id, span)
|
|
|
|
.map(|must_use_path| {
|
|
|
|
emit_must_use_untranslated(
|
|
|
|
cx,
|
|
|
|
&must_use_path,
|
|
|
|
descr_pre_path,
|
|
|
|
descr_post_path,
|
|
|
|
1,
|
2023-03-11 05:28:05 +00:00
|
|
|
false,
|
2023-06-11 15:44:28 +00:00
|
|
|
expr_is_from_block,
|
2022-11-13 12:02:52 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.is_some()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument(skip(cx), level = "debug")]
|
|
|
|
fn emit_must_use_untranslated(
|
|
|
|
cx: &LateContext<'_>,
|
|
|
|
path: &MustUsePath,
|
|
|
|
descr_pre: &str,
|
|
|
|
descr_post: &str,
|
|
|
|
plural_len: usize,
|
2023-03-11 05:28:05 +00:00
|
|
|
is_inner: bool,
|
2023-06-11 15:44:28 +00:00
|
|
|
expr_is_from_block: bool,
|
2022-11-13 12:02:52 +00:00
|
|
|
) {
|
|
|
|
let plural_suffix = pluralize!(plural_len);
|
|
|
|
|
|
|
|
match path {
|
|
|
|
MustUsePath::Suppressed => {}
|
|
|
|
MustUsePath::Boxed(path) => {
|
|
|
|
let descr_pre = &format!("{}boxed ", descr_pre);
|
2023-06-11 15:44:28 +00:00
|
|
|
emit_must_use_untranslated(
|
|
|
|
cx,
|
|
|
|
path,
|
|
|
|
descr_pre,
|
|
|
|
descr_post,
|
|
|
|
plural_len,
|
|
|
|
true,
|
|
|
|
expr_is_from_block,
|
|
|
|
);
|
2022-11-13 12:02:52 +00:00
|
|
|
}
|
|
|
|
MustUsePath::Opaque(path) => {
|
|
|
|
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
|
2023-06-11 15:44:28 +00:00
|
|
|
emit_must_use_untranslated(
|
|
|
|
cx,
|
|
|
|
path,
|
|
|
|
descr_pre,
|
|
|
|
descr_post,
|
|
|
|
plural_len,
|
|
|
|
true,
|
|
|
|
expr_is_from_block,
|
|
|
|
);
|
2022-11-13 12:02:52 +00:00
|
|
|
}
|
|
|
|
MustUsePath::TraitObject(path) => {
|
|
|
|
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
|
2023-06-11 15:44:28 +00:00
|
|
|
emit_must_use_untranslated(
|
|
|
|
cx,
|
|
|
|
path,
|
|
|
|
descr_pre,
|
|
|
|
descr_post,
|
|
|
|
plural_len,
|
|
|
|
true,
|
|
|
|
expr_is_from_block,
|
|
|
|
);
|
2022-11-13 12:02:52 +00:00
|
|
|
}
|
|
|
|
MustUsePath::TupleElement(elems) => {
|
|
|
|
for (index, path) in elems {
|
|
|
|
let descr_post = &format!(" in tuple element {}", index);
|
2023-03-11 05:28:05 +00:00
|
|
|
emit_must_use_untranslated(
|
2023-06-11 15:44:28 +00:00
|
|
|
cx,
|
|
|
|
path,
|
|
|
|
descr_pre,
|
|
|
|
descr_post,
|
|
|
|
plural_len,
|
|
|
|
true,
|
|
|
|
expr_is_from_block,
|
2023-03-11 05:28:05 +00:00
|
|
|
);
|
2022-11-13 12:02:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MustUsePath::Array(path, len) => {
|
|
|
|
let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix);
|
|
|
|
emit_must_use_untranslated(
|
|
|
|
cx,
|
|
|
|
path,
|
|
|
|
descr_pre,
|
|
|
|
descr_post,
|
|
|
|
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
|
2023-03-11 05:28:05 +00:00
|
|
|
true,
|
2023-06-11 15:44:28 +00:00
|
|
|
expr_is_from_block,
|
2022-11-13 12:02:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
MustUsePath::Closure(span) => {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
2022-09-16 07:01:02 +00:00
|
|
|
UNUSED_MUST_USE,
|
2022-11-13 12:02:52 +00:00
|
|
|
*span,
|
2022-09-04 19:46:35 +00:00
|
|
|
UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
|
2022-09-16 07:01:02 +00:00
|
|
|
);
|
2020-07-28 00:00:00 +00:00
|
|
|
}
|
2022-11-13 12:02:52 +00:00
|
|
|
MustUsePath::Generator(span) => {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
2022-09-16 07:01:02 +00:00
|
|
|
UNUSED_MUST_USE,
|
2022-11-13 12:02:52 +00:00
|
|
|
*span,
|
2022-09-04 19:46:35 +00:00
|
|
|
UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post },
|
2022-09-16 07:01:02 +00:00
|
|
|
);
|
2020-07-28 00:00:00 +00:00
|
|
|
}
|
2022-11-13 12:02:52 +00:00
|
|
|
MustUsePath::Def(span, def_id, reason) => {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
|
|
|
UNUSED_MUST_USE,
|
|
|
|
*span,
|
|
|
|
UnusedDef {
|
|
|
|
pre: descr_pre,
|
|
|
|
post: descr_post,
|
|
|
|
cx,
|
|
|
|
def_id: *def_id,
|
|
|
|
note: *reason,
|
2023-06-11 15:44:28 +00:00
|
|
|
suggestion: (!is_inner).then_some(if expr_is_from_block {
|
|
|
|
UnusedDefSuggestion::BlockTailExpr {
|
|
|
|
before_span: span.shrink_to_lo(),
|
|
|
|
after_span: span.shrink_to_hi(),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() }
|
|
|
|
}),
|
2022-09-04 19:46:35 +00:00
|
|
|
},
|
|
|
|
);
|
2022-11-13 12:02:52 +00:00
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `path_statements` lint detects path statements with no effect.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// let x = 42;
|
|
|
|
///
|
|
|
|
/// x;
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// It is usually a mistake to have a statement that has no effect.
|
2015-09-15 22:58:19 +00:00
|
|
|
pub PATH_STATEMENTS,
|
|
|
|
Warn,
|
|
|
|
"path statements with no effect"
|
|
|
|
}
|
|
|
|
|
2019-04-03 14:05:40 +00:00
|
|
|
declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for PathStatements {
|
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
2020-08-02 14:30:09 +00:00
|
|
|
if let hir::StmtKind::Semi(expr) = s.kind {
|
2019-09-26 13:39:48 +00:00
|
|
|
if let hir::ExprKind::Path(_) = expr.kind {
|
2022-09-16 07:01:02 +00:00
|
|
|
let ty = cx.typeck_results().expr_ty(expr);
|
|
|
|
if ty.needs_drop(cx.tcx, cx.param_env) {
|
2022-09-04 19:46:35 +00:00
|
|
|
let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
|
|
|
|
{
|
|
|
|
PathStatementDropSub::Suggestion { span: s.span, snippet }
|
|
|
|
} else {
|
|
|
|
PathStatementDropSub::Help { span: s.span }
|
|
|
|
};
|
|
|
|
cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
|
2022-09-16 07:01:02 +00:00
|
|
|
} else {
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
|
2022-09-16 07:01:02 +00:00
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum UnusedDelimsCtx {
|
|
|
|
FunctionArg,
|
|
|
|
MethodArg,
|
|
|
|
AssignedValue,
|
2021-07-30 22:12:11 +00:00
|
|
|
AssignedValueLetElse,
|
2020-03-27 20:54:52 +00:00
|
|
|
IfCond,
|
|
|
|
WhileCond,
|
2020-03-31 16:42:54 +00:00
|
|
|
ForIterExpr,
|
|
|
|
MatchScrutineeExpr,
|
2020-03-27 20:54:52 +00:00
|
|
|
ReturnValue,
|
|
|
|
BlockRetValue,
|
2020-03-31 16:42:54 +00:00
|
|
|
LetScrutineeExpr,
|
2020-03-27 20:54:52 +00:00
|
|
|
ArrayLenExpr,
|
|
|
|
AnonConst,
|
2022-08-03 04:00:04 +00:00
|
|
|
MatchArmExpr,
|
2023-01-31 23:48:08 +00:00
|
|
|
IndexExpr,
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
impl From<UnusedDelimsCtx> for &'static str {
|
|
|
|
fn from(ctx: UnusedDelimsCtx) -> &'static str {
|
|
|
|
match ctx {
|
|
|
|
UnusedDelimsCtx::FunctionArg => "function argument",
|
|
|
|
UnusedDelimsCtx::MethodArg => "method argument",
|
2021-07-30 22:12:11 +00:00
|
|
|
UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
|
|
|
|
"assigned value"
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
UnusedDelimsCtx::IfCond => "`if` condition",
|
|
|
|
UnusedDelimsCtx::WhileCond => "`while` condition",
|
2020-03-31 16:42:54 +00:00
|
|
|
UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
|
|
|
|
UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
|
2020-03-27 20:54:52 +00:00
|
|
|
UnusedDelimsCtx::ReturnValue => "`return` value",
|
|
|
|
UnusedDelimsCtx::BlockRetValue => "block return value",
|
2020-03-31 16:42:54 +00:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
|
2020-03-27 20:54:52 +00:00
|
|
|
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
|
2022-08-03 04:00:04 +00:00
|
|
|
UnusedDelimsCtx::MatchArmExpr => "match arm expression",
|
2023-01-31 23:48:08 +00:00
|
|
|
UnusedDelimsCtx::IndexExpr => "index expression",
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
/// Used by both `UnusedParens` and `UnusedBraces` to prevent code duplication.
|
|
|
|
trait UnusedDelimLint {
|
|
|
|
const DELIM_STR: &'static str;
|
|
|
|
|
2020-04-04 20:40:31 +00:00
|
|
|
/// Due to `ref` pattern, there can be a difference between using
|
|
|
|
/// `{ expr }` and `expr` in pattern-matching contexts. This means
|
|
|
|
/// that we should only lint `unused_parens` and not `unused_braces`
|
|
|
|
/// in this case.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// let mut a = 7;
|
|
|
|
/// let ref b = { a }; // We actually borrow a copy of `a` here.
|
|
|
|
/// a += 1; // By mutating `a` we invalidate any borrows of `a`.
|
|
|
|
/// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here.
|
|
|
|
/// ```
|
|
|
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool;
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
// this cannot be a constant is it refers to a static.
|
|
|
|
fn lint(&self) -> &'static Lint;
|
|
|
|
|
|
|
|
fn check_unused_delims_expr(
|
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
|
|
|
ctx: UnusedDelimsCtx,
|
|
|
|
followed_by_block: bool,
|
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>,
|
2023-06-05 14:25:00 +00:00
|
|
|
is_kw: bool,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
|
2021-07-30 22:12:11 +00:00
|
|
|
fn is_expr_delims_necessary(
|
|
|
|
inner: &ast::Expr,
|
|
|
|
followed_by_block: bool,
|
|
|
|
followed_by_else: bool,
|
|
|
|
) -> bool {
|
|
|
|
if followed_by_else {
|
|
|
|
match inner.kind {
|
|
|
|
ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
|
|
|
|
_ if classify::expr_trailing_brace(inner).is_some() => return true,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-12 20:53:38 +00:00
|
|
|
// Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
|
|
|
|
{
|
2020-05-05 23:50:55 +00:00
|
|
|
let mut innermost = inner;
|
|
|
|
loop {
|
2021-08-31 21:45:57 +00:00
|
|
|
innermost = match &innermost.kind {
|
2023-04-12 20:53:38 +00:00
|
|
|
ExprKind::Binary(_op, lhs, _rhs) => lhs,
|
2021-08-31 21:45:57 +00:00
|
|
|
ExprKind::Call(fn_, _params) => fn_,
|
|
|
|
ExprKind::Cast(expr, _ty) => expr,
|
|
|
|
ExprKind::Type(expr, _ty) => expr,
|
|
|
|
ExprKind::Index(base, _subscript) => base,
|
2023-04-12 20:53:38 +00:00
|
|
|
_ => break,
|
2021-08-31 21:45:57 +00:00
|
|
|
};
|
|
|
|
if !classify::expr_requires_semi_to_be_stmt(innermost) {
|
2023-04-12 20:53:38 +00:00
|
|
|
return true;
|
2020-05-05 23:50:55 +00:00
|
|
|
}
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
2023-04-12 20:53:38 +00:00
|
|
|
}
|
2020-05-05 23:50:55 +00:00
|
|
|
|
2023-04-12 20:53:38 +00:00
|
|
|
// Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`.
|
|
|
|
if !followed_by_block {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let mut innermost = inner;
|
|
|
|
loop {
|
|
|
|
innermost = match &innermost.kind {
|
|
|
|
ExprKind::Unary(_op, expr) => expr,
|
|
|
|
ExprKind::Binary(_op, _lhs, rhs) => rhs,
|
|
|
|
ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
|
|
|
|
ExprKind::Assign(_lhs, rhs, _span) => rhs,
|
|
|
|
|
2023-04-12 21:53:18 +00:00
|
|
|
ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true,
|
|
|
|
|
|
|
|
ExprKind::Break(_label, None) => return false,
|
|
|
|
ExprKind::Break(_label, Some(break_expr)) => {
|
|
|
|
return matches!(break_expr.kind, ExprKind::Block(..));
|
|
|
|
}
|
2023-04-12 20:53:38 +00:00
|
|
|
|
|
|
|
ExprKind::Range(_lhs, Some(rhs), _limits) => {
|
|
|
|
return matches!(rhs.kind, ExprKind::Block(..));
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => return parser::contains_exterior_struct_lit(&inner),
|
|
|
|
}
|
|
|
|
}
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
fn emit_unused_delims_expr(
|
2018-10-02 05:32:26 +00:00
|
|
|
&self,
|
2019-08-02 17:46:09 +00:00
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
2020-03-27 20:54:52 +00:00
|
|
|
ctx: UnusedDelimsCtx,
|
2019-08-02 17:46:09 +00:00
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>,
|
2023-06-05 14:25:00 +00:00
|
|
|
is_kw: bool,
|
2019-08-02 17:46:09 +00:00
|
|
|
) {
|
2022-11-28 07:14:20 +00:00
|
|
|
// If `value` has `ExprKind::Err`, unused delim lint can be broken.
|
|
|
|
// For example, the following code caused ICE.
|
|
|
|
// This is because the `ExprKind::Call` in `value` has `ExprKind::Err` as its argument
|
|
|
|
// and this leads to wrong spans. #104897
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// fn f(){(print!(á
|
|
|
|
// ```
|
|
|
|
use rustc_ast::visit::{walk_expr, Visitor};
|
|
|
|
struct ErrExprVisitor {
|
|
|
|
has_error: bool,
|
|
|
|
}
|
|
|
|
impl<'ast> Visitor<'ast> for ErrExprVisitor {
|
|
|
|
fn visit_expr(&mut self, expr: &'ast ast::Expr) {
|
|
|
|
if let ExprKind::Err = expr.kind {
|
|
|
|
self.has_error = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
walk_expr(self, expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut visitor = ErrExprVisitor { has_error: false };
|
|
|
|
visitor.visit_expr(value);
|
|
|
|
if visitor.has_error {
|
|
|
|
return;
|
|
|
|
}
|
2021-09-09 14:22:24 +00:00
|
|
|
let spans = match value.kind {
|
2023-04-15 18:18:30 +00:00
|
|
|
ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
|
|
|
|
.span
|
|
|
|
.find_ancestor_inside(value.span)
|
|
|
|
.map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
|
2021-09-09 14:22:24 +00:00
|
|
|
ast::ExprKind::Paren(ref expr) => {
|
2023-04-15 18:18:30 +00:00
|
|
|
expr.span.find_ancestor_inside(value.span).map(|expr_span| {
|
|
|
|
(value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))
|
|
|
|
})
|
2021-09-09 14:22:24 +00:00
|
|
|
}
|
|
|
|
_ => return,
|
2020-03-27 20:54:52 +00:00
|
|
|
};
|
|
|
|
let keep_space = (
|
2023-05-24 14:19:22 +00:00
|
|
|
left_pos.is_some_and(|s| s >= value.span.lo()),
|
|
|
|
right_pos.is_some_and(|s| s <= value.span.hi()),
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
2023-06-05 14:25:00 +00:00
|
|
|
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space, is_kw);
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
2018-10-02 05:32:26 +00:00
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
fn emit_unused_delims(
|
2019-09-03 13:33:30 +00:00
|
|
|
&self,
|
2019-08-02 18:17:20 +00:00
|
|
|
cx: &EarlyContext<'_>,
|
2022-08-07 10:36:54 +00:00
|
|
|
value_span: Span,
|
|
|
|
spans: Option<(Span, Span)>,
|
2019-08-02 18:17:20 +00:00
|
|
|
msg: &str,
|
|
|
|
keep_space: (bool, bool),
|
2023-06-05 14:25:00 +00:00
|
|
|
is_kw: bool,
|
2019-08-02 18:17:20 +00:00
|
|
|
) {
|
2022-08-07 10:36:54 +00:00
|
|
|
let primary_span = if let Some((lo, hi)) = spans {
|
2023-02-04 12:27:53 +00:00
|
|
|
if hi.is_empty() {
|
|
|
|
// do not point at delims that do not exist
|
|
|
|
return;
|
|
|
|
}
|
2022-08-07 10:36:54 +00:00
|
|
|
MultiSpan::from(vec![lo, hi])
|
|
|
|
} else {
|
|
|
|
MultiSpan::from(value_span)
|
|
|
|
};
|
2022-09-04 19:46:35 +00:00
|
|
|
let suggestion = spans.map(|(lo, hi)| {
|
|
|
|
let sm = cx.sess().source_map();
|
|
|
|
let lo_replace =
|
2023-06-05 14:25:00 +00:00
|
|
|
if (keep_space.0 || is_kw) &&
|
2022-11-18 09:30:47 +00:00
|
|
|
let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') {
|
2022-09-04 19:46:35 +00:00
|
|
|
" "
|
2022-10-24 08:48:28 +00:00
|
|
|
} else {
|
2022-09-04 19:46:35 +00:00
|
|
|
""
|
2022-10-24 08:48:28 +00:00
|
|
|
};
|
|
|
|
|
2022-09-04 19:46:35 +00:00
|
|
|
let hi_replace =
|
2022-10-24 08:48:28 +00:00
|
|
|
if keep_space.1 &&
|
2022-11-18 09:30:47 +00:00
|
|
|
let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') {
|
2022-09-04 19:46:35 +00:00
|
|
|
" "
|
2022-10-24 08:48:28 +00:00
|
|
|
} else {
|
2022-09-04 19:46:35 +00:00
|
|
|
""
|
2022-10-24 08:48:28 +00:00
|
|
|
};
|
2022-09-04 19:46:35 +00:00
|
|
|
UnusedDelimSuggestion {
|
|
|
|
start_span: lo,
|
|
|
|
start_replace: lo_replace,
|
|
|
|
end_span: hi,
|
|
|
|
end_replace: hi_replace,
|
2022-08-07 10:36:54 +00:00
|
|
|
}
|
2020-01-31 12:24:57 +00:00
|
|
|
});
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
|
|
|
self.lint(),
|
|
|
|
primary_span,
|
|
|
|
UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion },
|
|
|
|
);
|
2018-10-04 16:36:55 +00:00
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2019-02-08 11:35:41 +00:00
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
2020-04-27 17:56:11 +00:00
|
|
|
use rustc_ast::ExprKind::*;
|
2023-06-05 14:25:00 +00:00
|
|
|
let (value, ctx, followed_by_block, left_pos, right_pos, is_kw) = match e.kind {
|
2020-04-04 20:40:31 +00:00
|
|
|
// Do not lint `unused_braces` in `if let` expressions.
|
2021-03-07 02:29:41 +00:00
|
|
|
If(ref cond, ref block, _)
|
2021-08-08 14:49:13 +00:00
|
|
|
if !matches!(cond.kind, Let(_, _, _))
|
|
|
|
|| Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
2020-04-04 20:40:31 +00:00
|
|
|
{
|
2019-12-31 17:15:40 +00:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(2);
|
2019-08-02 17:46:09 +00:00
|
|
|
let right = block.span.lo();
|
2023-06-05 14:25:00 +00:00
|
|
|
(cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right), true)
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2020-08-03 03:18:10 +00:00
|
|
|
// Do not lint `unused_braces` in `while let` expressions.
|
|
|
|
While(ref cond, ref block, ..)
|
2021-08-08 14:49:13 +00:00
|
|
|
if !matches!(cond.kind, Let(_, _, _))
|
|
|
|
|| Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
2020-08-03 03:18:10 +00:00
|
|
|
{
|
2019-12-31 17:15:40 +00:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(5);
|
2019-08-02 17:46:09 +00:00
|
|
|
let right = block.span.lo();
|
2023-06-05 14:25:00 +00:00
|
|
|
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
ForLoop(_, ref cond, ref block, ..) => {
|
2023-06-05 14:25:00 +00:00
|
|
|
(cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true)
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 20:40:31 +00:00
|
|
|
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
2019-12-31 17:15:40 +00:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(5);
|
2023-06-05 14:25:00 +00:00
|
|
|
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret(Some(ref value)) => {
|
2019-12-31 17:15:40 +00:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(3);
|
2023-06-05 14:25:00 +00:00
|
|
|
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
|
2019-08-02 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2023-06-05 14:25:00 +00:00
|
|
|
Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
|
2023-01-31 23:48:08 +00:00
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
Assign(_, ref value, _) | AssignOp(.., ref value) => {
|
2023-06-05 14:25:00 +00:00
|
|
|
(value, UnusedDelimsCtx::AssignedValue, false, None, None, false)
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
wherein the parens lint keeps its own counsel re args in nested macros
In #46980 ("in which the unused-parens lint..." (14982db2d6)), the
unused-parens lint was made to check function and method arguments,
which it previously did not (seemingly due to oversight rather than
willful design). However, in #47775 and discussion thereon,
user–developers of Geal/nom and graphql-rust/juniper reported that the
lint was seemingly erroneously triggering on certain complex macros in
those projects. While this doesn't seem like a bug in the lint in the
particular strict sense that the expanded code would, in fact, contain
unncecessary parentheses, it also doesn't seem like the sort of thing
macro authors should have to think about: the spirit of the
unused-parens lint is to prevent needless clutter in code, not to give
macro authors extra heartache in the handling of token trees.
We propose the expediency of declining to lint unused parentheses in
function or method args inside of nested expansions: we believe that
this should eliminate the petty, troublesome lint warnings reported
in the issue, without forgoing the benefits of the lint in simpler
macros.
It seemed like too much duplicated code for the `Call` and `MethodCall`
match arms to duplicate the nested-macro check in addition to each
having their own `for` loop, so this occasioned a slight refactor so
that the function and method cases could share code—hopefully the
overall intent is at least no less clear to the gentle reader.
This is concerning #47775.
2018-01-31 01:13:05 +00:00
|
|
|
// either function/method call, or something this lint doesn't care about
|
|
|
|
ref call_or_other => {
|
2020-03-27 20:54:52 +00:00
|
|
|
let (args_to_check, ctx) = match *call_or_other {
|
|
|
|
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
|
2022-09-08 00:52:51 +00:00
|
|
|
MethodCall(ref call) => (&call.args[..], UnusedDelimsCtx::MethodArg),
|
wherein the parens lint keeps its own counsel re args in nested macros
In #46980 ("in which the unused-parens lint..." (14982db2d6)), the
unused-parens lint was made to check function and method arguments,
which it previously did not (seemingly due to oversight rather than
willful design). However, in #47775 and discussion thereon,
user–developers of Geal/nom and graphql-rust/juniper reported that the
lint was seemingly erroneously triggering on certain complex macros in
those projects. While this doesn't seem like a bug in the lint in the
particular strict sense that the expanded code would, in fact, contain
unncecessary parentheses, it also doesn't seem like the sort of thing
macro authors should have to think about: the spirit of the
unused-parens lint is to prevent needless clutter in code, not to give
macro authors extra heartache in the handling of token trees.
We propose the expediency of declining to lint unused parentheses in
function or method args inside of nested expansions: we believe that
this should eliminate the petty, troublesome lint warnings reported
in the issue, without forgoing the benefits of the lint in simpler
macros.
It seemed like too much duplicated code for the `Call` and `MethodCall`
match arms to duplicate the nested-macro check in addition to each
having their own `for` loop, so this occasioned a slight refactor so
that the function and method cases could share code—hopefully the
overall intent is at least no less clear to the gentle reader.
This is concerning #47775.
2018-01-31 01:13:05 +00:00
|
|
|
// actual catch-all arm
|
2018-10-06 02:09:14 +00:00
|
|
|
_ => {
|
|
|
|
return;
|
|
|
|
}
|
2018-10-01 21:15:22 +00:00
|
|
|
};
|
wherein the parens lint keeps its own counsel re args in nested macros
In #46980 ("in which the unused-parens lint..." (14982db2d6)), the
unused-parens lint was made to check function and method arguments,
which it previously did not (seemingly due to oversight rather than
willful design). However, in #47775 and discussion thereon,
user–developers of Geal/nom and graphql-rust/juniper reported that the
lint was seemingly erroneously triggering on certain complex macros in
those projects. While this doesn't seem like a bug in the lint in the
particular strict sense that the expanded code would, in fact, contain
unncecessary parentheses, it also doesn't seem like the sort of thing
macro authors should have to think about: the spirit of the
unused-parens lint is to prevent needless clutter in code, not to give
macro authors extra heartache in the handling of token trees.
We propose the expediency of declining to lint unused parentheses in
function or method args inside of nested expansions: we believe that
this should eliminate the petty, troublesome lint warnings reported
in the issue, without forgoing the benefits of the lint in simpler
macros.
It seemed like too much duplicated code for the `Call` and `MethodCall`
match arms to duplicate the nested-macro check in addition to each
having their own `for` loop, so this occasioned a slight refactor so
that the function and method cases could share code—hopefully the
overall intent is at least no less clear to the gentle reader.
This is concerning #47775.
2018-01-31 01:13:05 +00:00
|
|
|
// Don't lint if this is a nested macro expansion: otherwise, the lint could
|
|
|
|
// trigger in situations that macro authors shouldn't have to care about, e.g.,
|
|
|
|
// when a parenthesized token tree matched in one macro expansion is matched as
|
|
|
|
// an expression in another and used as a fn/method argument (Issue #47775)
|
2019-08-13 20:56:42 +00:00
|
|
|
if e.span.ctxt().outer_expn_data().call_site.from_expansion() {
|
2019-08-11 00:00:05 +00:00
|
|
|
return;
|
wherein the parens lint keeps its own counsel re args in nested macros
In #46980 ("in which the unused-parens lint..." (14982db2d6)), the
unused-parens lint was made to check function and method arguments,
which it previously did not (seemingly due to oversight rather than
willful design). However, in #47775 and discussion thereon,
user–developers of Geal/nom and graphql-rust/juniper reported that the
lint was seemingly erroneously triggering on certain complex macros in
those projects. While this doesn't seem like a bug in the lint in the
particular strict sense that the expanded code would, in fact, contain
unncecessary parentheses, it also doesn't seem like the sort of thing
macro authors should have to think about: the spirit of the
unused-parens lint is to prevent needless clutter in code, not to give
macro authors extra heartache in the handling of token trees.
We propose the expediency of declining to lint unused parentheses in
function or method args inside of nested expansions: we believe that
this should eliminate the petty, troublesome lint warnings reported
in the issue, without forgoing the benefits of the lint in simpler
macros.
It seemed like too much duplicated code for the `Call` and `MethodCall`
match arms to duplicate the nested-macro check in addition to each
having their own `for` loop, so this occasioned a slight refactor so
that the function and method cases could share code—hopefully the
overall intent is at least no less clear to the gentle reader.
This is concerning #47775.
2018-01-31 01:13:05 +00:00
|
|
|
}
|
|
|
|
for arg in args_to_check {
|
2023-06-05 14:25:00 +00:00
|
|
|
self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false);
|
2017-12-24 03:28:33 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
};
|
2023-06-05 14:25:00 +00:00
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&value,
|
|
|
|
ctx,
|
|
|
|
followed_by_block,
|
|
|
|
left_pos,
|
|
|
|
right_pos,
|
|
|
|
is_kw,
|
|
|
|
);
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
match s.kind {
|
2020-04-04 20:40:31 +00:00
|
|
|
StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
2021-07-30 22:12:11 +00:00
|
|
|
if let Some((init, els)) = local.kind.init_else_opt() {
|
|
|
|
let ctx = match els {
|
|
|
|
None => UnusedDelimsCtx::AssignedValue,
|
|
|
|
Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
|
|
|
|
};
|
2023-06-05 14:25:00 +00:00
|
|
|
self.check_unused_delims_expr(cx, init, ctx, false, None, None, false);
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
StmtKind::Expr(ref expr) => {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&expr,
|
|
|
|
UnusedDelimsCtx::BlockRetValue,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
|
|
|
use ast::ItemKind::*;
|
|
|
|
|
2023-03-29 12:34:05 +00:00
|
|
|
if let Const(box ast::ConstItem { expr: Some(expr), .. })
|
2023-03-29 14:14:11 +00:00
|
|
|
| Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind
|
2023-03-29 09:20:45 +00:00
|
|
|
{
|
2020-03-27 20:54:52 +00:00
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
|
|
|
UnusedDelimsCtx::AssignedValue,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_parens` lint detects `if`, `match`, `while` and `return`
|
|
|
|
/// with parentheses; they do not need them.
|
|
|
|
///
|
|
|
|
/// ### Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// if(true) {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
2021-10-17 10:04:01 +00:00
|
|
|
/// The parentheses are not needed, and should be removed. This is the
|
2020-09-08 22:09:57 +00:00
|
|
|
/// preferred style for writing these expressions.
|
2020-03-27 20:54:52 +00:00
|
|
|
pub(super) UNUSED_PARENS,
|
|
|
|
Warn,
|
|
|
|
"`if`, `match`, `while` and `return` do not need parentheses"
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:52:46 +00:00
|
|
|
pub struct UnusedParens {
|
|
|
|
with_self_ty_parens: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UnusedParens {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self { with_self_ty_parens: false }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
|
2020-03-27 20:54:52 +00:00
|
|
|
|
|
|
|
impl UnusedDelimLint for UnusedParens {
|
|
|
|
const DELIM_STR: &'static str = "parentheses";
|
|
|
|
|
2020-04-04 20:40:31 +00:00
|
|
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
fn lint(&self) -> &'static Lint {
|
|
|
|
UNUSED_PARENS
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_unused_delims_expr(
|
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
|
|
|
ctx: UnusedDelimsCtx,
|
|
|
|
followed_by_block: bool,
|
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>,
|
2023-06-05 14:25:00 +00:00
|
|
|
is_kw: bool,
|
2020-03-27 20:54:52 +00:00
|
|
|
) {
|
|
|
|
match value.kind {
|
|
|
|
ast::ExprKind::Paren(ref inner) => {
|
2021-07-30 22:12:11 +00:00
|
|
|
let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
|
|
|
|
if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else)
|
2020-03-27 20:54:52 +00:00
|
|
|
&& value.attrs.is_empty()
|
|
|
|
&& !value.span.from_expansion()
|
2020-10-13 23:13:48 +00:00
|
|
|
&& (ctx != UnusedDelimsCtx::LetScrutineeExpr
|
2020-10-27 00:02:06 +00:00
|
|
|
|| !matches!(inner.kind, ast::ExprKind::Binary(
|
2020-10-13 23:13:48 +00:00
|
|
|
rustc_span::source_map::Spanned { node, .. },
|
|
|
|
_,
|
|
|
|
_,
|
2020-10-27 00:02:06 +00:00
|
|
|
) if node.lazy()))
|
2020-03-27 20:54:52 +00:00
|
|
|
{
|
2023-06-05 14:25:00 +00:00
|
|
|
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-08 14:49:13 +00:00
|
|
|
ast::ExprKind::Let(_, ref expr, _) => {
|
2020-03-27 20:54:52 +00:00
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
2020-03-31 16:42:54 +00:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr,
|
2020-03-27 20:54:52 +00:00
|
|
|
followed_by_block,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UnusedParens {
|
|
|
|
fn check_unused_parens_pat(
|
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Pat,
|
|
|
|
avoid_or: bool,
|
|
|
|
avoid_mut: bool,
|
2022-10-24 08:48:28 +00:00
|
|
|
keep_space: (bool, bool),
|
2020-03-27 20:54:52 +00:00
|
|
|
) {
|
2022-08-30 22:34:35 +00:00
|
|
|
use ast::{BindingAnnotation, PatKind};
|
2020-03-27 20:54:52 +00:00
|
|
|
|
|
|
|
if let PatKind::Paren(inner) = &value.kind {
|
|
|
|
match inner.kind {
|
|
|
|
// The lint visitor will visit each subpattern of `p`. We do not want to lint
|
|
|
|
// any range pattern no matter where it occurs in the pattern. For something like
|
|
|
|
// `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
|
|
|
|
// that if there are unnecessary parens they serve a purpose of readability.
|
|
|
|
PatKind::Range(..) => return,
|
|
|
|
// Avoid `p0 | .. | pn` if we should.
|
|
|
|
PatKind::Or(..) if avoid_or => return,
|
|
|
|
// Avoid `mut x` and `mut x @ p` if we should:
|
2022-08-30 22:34:35 +00:00
|
|
|
PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => {
|
|
|
|
return;
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
// Otherwise proceed with linting.
|
|
|
|
_ => {}
|
|
|
|
}
|
2023-04-15 18:18:30 +00:00
|
|
|
let spans = inner
|
|
|
|
.span
|
|
|
|
.find_ancestor_inside(value.span)
|
|
|
|
.map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())));
|
2023-06-05 14:25:00 +00:00
|
|
|
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false);
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedParens {
|
2022-12-07 03:52:28 +00:00
|
|
|
#[inline]
|
2020-03-27 20:54:52 +00:00
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
2021-03-07 02:29:41 +00:00
|
|
|
match e.kind {
|
2021-08-08 14:49:13 +00:00
|
|
|
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
|
2021-03-07 02:29:41 +00:00
|
|
|
}
|
|
|
|
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
|
|
|
|
// handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
|
|
|
|
// want to complain about things like `if let 42 = (42)`.
|
|
|
|
ExprKind::If(ref cond, ref block, ref else_)
|
|
|
|
if matches!(cond.peel_parens().kind, ExprKind::Let(..)) =>
|
|
|
|
{
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
cond.peel_parens(),
|
|
|
|
UnusedDelimsCtx::LetScrutineeExpr,
|
|
|
|
true,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
true,
|
2021-03-07 02:29:41 +00:00
|
|
|
);
|
|
|
|
for stmt in &block.stmts {
|
|
|
|
<Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
|
|
|
|
}
|
|
|
|
if let Some(e) = else_ {
|
|
|
|
<Self as UnusedDelimLint>::check_expr(self, cx, e);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2022-08-03 04:00:04 +00:00
|
|
|
ExprKind::Match(ref _expr, ref arm) => {
|
|
|
|
for a in arm {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&a.body,
|
|
|
|
UnusedDelimsCtx::MatchArmExpr,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
true,
|
2022-08-03 04:00:04 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2021-03-07 02:29:41 +00:00
|
|
|
_ => {}
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
<Self as UnusedDelimLint>::check_expr(self, cx, e)
|
2018-10-02 05:32:26 +00:00
|
|
|
}
|
|
|
|
|
2019-04-21 14:09:30 +00:00
|
|
|
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
|
2019-09-03 13:33:30 +00:00
|
|
|
use ast::{Mutability, PatKind::*};
|
2022-10-24 08:48:28 +00:00
|
|
|
let keep_space = (false, false);
|
2019-09-26 15:18:31 +00:00
|
|
|
match &p.kind {
|
2019-09-03 13:33:30 +00:00
|
|
|
// Do not lint on `(..)` as that will result in the other arms being useless.
|
|
|
|
Paren(_)
|
|
|
|
// The other cases do not contain sub-patterns.
|
2020-03-20 14:03:11 +00:00
|
|
|
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
2019-09-03 13:33:30 +00:00
|
|
|
// These are list-like patterns; parens can always be removed.
|
2020-12-10 12:20:07 +00:00
|
|
|
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
2019-09-03 13:33:30 +00:00
|
|
|
},
|
2020-12-10 12:20:07 +00:00
|
|
|
Struct(_, _, fps, _) => for f in fps {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
|
2019-09-03 13:33:30 +00:00
|
|
|
},
|
|
|
|
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
2022-10-24 08:48:28 +00:00
|
|
|
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
2019-09-03 13:33:30 +00:00
|
|
|
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
|
|
|
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
2022-10-24 08:48:28 +00:00
|
|
|
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
2018-10-06 02:09:14 +00:00
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
if let StmtKind::Local(ref local) = s.kind {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
|
2018-10-01 21:15:22 +00:00
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
|
|
|
|
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
2019-09-03 13:33:30 +00:00
|
|
|
|
|
|
|
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, ¶m.pat, true, false, (false, false));
|
2019-09-03 13:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
|
2022-10-24 08:48:28 +00:00
|
|
|
self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
|
2019-09-03 13:33:30 +00:00
|
|
|
}
|
2019-10-04 05:56:57 +00:00
|
|
|
|
|
|
|
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
2023-01-16 12:44:14 +00:00
|
|
|
match &ty.kind {
|
|
|
|
ast::TyKind::Array(_, len) => {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&len.value,
|
|
|
|
UnusedDelimsCtx::ArrayLenExpr,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2023-01-16 12:44:14 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
ast::TyKind::Paren(r) => {
|
|
|
|
match &r.kind {
|
|
|
|
ast::TyKind::TraitObject(..) => {}
|
|
|
|
ast::TyKind::BareFn(b)
|
|
|
|
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
|
|
|
|
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
|
|
|
|
_ => {
|
2023-04-15 18:18:30 +00:00
|
|
|
let spans = r
|
|
|
|
.span
|
|
|
|
.find_ancestor_inside(ty.span)
|
|
|
|
.map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())));
|
|
|
|
|
2023-06-05 14:25:00 +00:00
|
|
|
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
|
2023-01-16 12:44:14 +00:00
|
|
|
}
|
2019-10-04 05:56:57 +00:00
|
|
|
}
|
2023-01-16 12:44:14 +00:00
|
|
|
self.with_self_ty_parens = false;
|
2019-10-04 05:56:57 +00:00
|
|
|
}
|
2023-01-16 12:44:14 +00:00
|
|
|
_ => {}
|
2019-10-04 05:56:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-01 23:30:52 +00:00
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
2020-03-27 20:54:52 +00:00
|
|
|
<Self as UnusedDelimLint>::check_item(self, cx, item)
|
|
|
|
}
|
2023-01-14 08:52:46 +00:00
|
|
|
|
|
|
|
fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
|
|
|
|
use rustc_ast::{WhereBoundPredicate, WherePredicate};
|
|
|
|
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
|
|
|
|
bounded_ty,
|
|
|
|
bound_generic_params,
|
|
|
|
..
|
|
|
|
}) = pred &&
|
|
|
|
let ast::TyKind::Paren(_) = &bounded_ty.kind &&
|
|
|
|
bound_generic_params.is_empty() {
|
|
|
|
self.with_self_ty_parens = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) {
|
2023-01-16 12:44:14 +00:00
|
|
|
assert!(!self.with_self_ty_parens);
|
2023-01-14 08:52:46 +00:00
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
2020-02-01 23:30:52 +00:00
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_braces` lint detects unnecessary braces around an
|
|
|
|
/// expression.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// if { true } {
|
|
|
|
/// // ...
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// The braces are not needed, and should be removed. This is the
|
|
|
|
/// preferred style for writing these expressions.
|
2020-03-27 20:54:52 +00:00
|
|
|
pub(super) UNUSED_BRACES,
|
|
|
|
Warn,
|
2020-03-31 16:42:54 +00:00
|
|
|
"unnecessary braces around an expression"
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
|
|
|
|
|
|
|
|
impl UnusedDelimLint for UnusedBraces {
|
|
|
|
const DELIM_STR: &'static str = "braces";
|
|
|
|
|
2020-04-04 20:40:31 +00:00
|
|
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
|
|
|
|
|
2020-03-27 20:54:52 +00:00
|
|
|
fn lint(&self) -> &'static Lint {
|
|
|
|
UNUSED_BRACES
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_unused_delims_expr(
|
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
|
|
|
ctx: UnusedDelimsCtx,
|
|
|
|
followed_by_block: bool,
|
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>,
|
2023-06-05 14:25:00 +00:00
|
|
|
is_kw: bool,
|
2020-03-27 20:54:52 +00:00
|
|
|
) {
|
|
|
|
match value.kind {
|
|
|
|
ast::ExprKind::Block(ref inner, None)
|
|
|
|
if inner.rules == ast::BlockCheckMode::Default =>
|
|
|
|
{
|
|
|
|
// emit a warning under the following conditions:
|
|
|
|
//
|
|
|
|
// - the block does not have a label
|
|
|
|
// - the block is not `unsafe`
|
|
|
|
// - the block contains exactly one expression (do not lint `{ expr; }`)
|
|
|
|
// - `followed_by_block` is true and the internal expr may contain a `{`
|
|
|
|
// - the block is not multiline (do not lint multiline match arms)
|
|
|
|
// ```
|
|
|
|
// match expr {
|
|
|
|
// Pattern => {
|
|
|
|
// somewhat_long_expression
|
|
|
|
// }
|
|
|
|
// // ...
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
// - the block has no attribute and was not created inside a macro
|
|
|
|
// - if the block is an `anon_const`, the inner expr must be a literal
|
2023-01-15 05:06:33 +00:00
|
|
|
// not created by a macro, i.e. do not lint on:
|
|
|
|
// ```
|
|
|
|
// struct A<const N: usize>;
|
|
|
|
// let _: A<{ 2 + 3 }>;
|
|
|
|
// let _: A<{produces_literal!()}>;
|
|
|
|
// ```
|
2020-03-27 20:54:52 +00:00
|
|
|
// FIXME(const_generics): handle paths when #67075 is fixed.
|
|
|
|
if let [stmt] = inner.stmts.as_slice() {
|
|
|
|
if let ast::StmtKind::Expr(ref expr) = stmt.kind {
|
2021-07-30 22:12:11 +00:00
|
|
|
if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
|
2020-03-27 20:54:52 +00:00
|
|
|
&& (ctx != UnusedDelimsCtx::AnonConst
|
2023-01-15 05:06:33 +00:00
|
|
|
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
|
|
|
|
&& !expr.span.from_expansion()))
|
2020-03-27 20:54:52 +00:00
|
|
|
&& !cx.sess().source_map().is_multiline(value.span)
|
|
|
|
&& value.attrs.is_empty()
|
|
|
|
&& !value.span.from_expansion()
|
2022-12-09 23:21:12 +00:00
|
|
|
&& !inner.span.from_expansion()
|
2020-03-27 20:54:52 +00:00
|
|
|
{
|
2023-06-05 14:25:00 +00:00
|
|
|
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-08 14:49:13 +00:00
|
|
|
ast::ExprKind::Let(_, ref expr, _) => {
|
2020-03-27 20:54:52 +00:00
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
2020-03-31 16:42:54 +00:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr,
|
2020-03-27 20:54:52 +00:00
|
|
|
followed_by_block,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedBraces {
|
2020-10-09 22:21:40 +00:00
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
|
|
|
}
|
|
|
|
|
2022-12-07 03:52:28 +00:00
|
|
|
#[inline]
|
2020-03-27 20:54:52 +00:00
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
2020-10-09 22:21:40 +00:00
|
|
|
<Self as UnusedDelimLint>::check_expr(self, cx, e);
|
|
|
|
|
|
|
|
if let ExprKind::Repeat(_, ref anon_const) = e.kind {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&anon_const.value,
|
|
|
|
UnusedDelimsCtx::AnonConst,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-10-09 22:21:40 +00:00
|
|
|
);
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 22:21:40 +00:00
|
|
|
fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
|
|
|
|
if let ast::GenericArg::Const(ct) = arg {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&ct.value,
|
|
|
|
UnusedDelimsCtx::AnonConst,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-10-09 22:21:40 +00:00
|
|
|
);
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 22:21:40 +00:00
|
|
|
fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
|
|
|
|
if let Some(anon_const) = &v.disr_expr {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&anon_const.value,
|
|
|
|
UnusedDelimsCtx::AnonConst,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-10-09 22:21:40 +00:00
|
|
|
);
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
2020-10-09 22:21:40 +00:00
|
|
|
match ty.kind {
|
|
|
|
ast::TyKind::Array(_, ref len) => {
|
2020-03-27 20:54:52 +00:00
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&len.value,
|
|
|
|
UnusedDelimsCtx::ArrayLenExpr,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-03-27 20:54:52 +00:00
|
|
|
);
|
|
|
|
}
|
2020-10-09 22:21:40 +00:00
|
|
|
|
|
|
|
ast::TyKind::Typeof(ref anon_const) => {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&anon_const.value,
|
|
|
|
UnusedDelimsCtx::AnonConst,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
2023-06-05 14:25:00 +00:00
|
|
|
false,
|
2020-10-09 22:21:40 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
2020-02-01 23:30:52 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 20:54:52 +00:00
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
|
|
|
<Self as UnusedDelimLint>::check_item(self, cx, item)
|
|
|
|
}
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_import_braces` lint catches unnecessary braces around an
|
|
|
|
/// imported item.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust,compile_fail
|
|
|
|
/// #![deny(unused_import_braces)]
|
|
|
|
/// use test::{A};
|
|
|
|
///
|
|
|
|
/// pub mod test {
|
|
|
|
/// pub struct A;
|
|
|
|
/// }
|
|
|
|
/// # fn main() {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// If there is only a single item, then remove the braces (`use test::A;`
|
|
|
|
/// for example).
|
|
|
|
///
|
|
|
|
/// This lint is "allow" by default because it is only enforcing a
|
|
|
|
/// stylistic choice.
|
2015-09-15 22:58:19 +00:00
|
|
|
UNUSED_IMPORT_BRACES,
|
|
|
|
Allow,
|
|
|
|
"unnecessary braces around an imported item"
|
|
|
|
}
|
|
|
|
|
2019-04-03 14:05:40 +00:00
|
|
|
declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2017-09-26 21:04:00 +00:00
|
|
|
impl UnusedImportBraces {
|
2019-02-08 11:35:41 +00:00
|
|
|
fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
|
2017-09-26 21:04:00 +00:00
|
|
|
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
|
|
|
// Recursively check nested UseTrees
|
2022-12-18 16:01:58 +00:00
|
|
|
for (tree, _) in items {
|
2017-09-26 21:04:00 +00:00
|
|
|
self.check_use_tree(cx, tree, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigger the lint only if there is one nested item
|
|
|
|
if items.len() != 1 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigger the lint if the nested item is a non-self single item
|
2019-09-14 20:10:12 +00:00
|
|
|
let node_name = match items[0].0.kind {
|
2022-12-01 15:51:20 +00:00
|
|
|
ast::UseTreeKind::Simple(rename) => {
|
2018-03-18 22:21:30 +00:00
|
|
|
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
|
2019-05-11 14:41:37 +00:00
|
|
|
if orig_ident.name == kw::SelfLower {
|
2017-09-26 21:04:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-09-14 20:10:12 +00:00
|
|
|
rename.unwrap_or(orig_ident).name
|
2017-09-26 21:04:00 +00:00
|
|
|
}
|
2019-09-14 20:10:12 +00:00
|
|
|
ast::UseTreeKind::Glob => Symbol::intern("*"),
|
|
|
|
ast::UseTreeKind::Nested(_) => return,
|
|
|
|
};
|
2017-09-26 21:04:00 +00:00
|
|
|
|
2022-09-04 19:46:35 +00:00
|
|
|
cx.emit_spanned_lint(
|
2022-09-16 07:01:02 +00:00
|
|
|
UNUSED_IMPORT_BRACES,
|
|
|
|
item.span,
|
2022-09-04 19:46:35 +00:00
|
|
|
UnusedImportBracesDiag { node: node_name },
|
2022-09-16 07:01:02 +00:00
|
|
|
);
|
2017-09-26 21:04:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-24 04:11:31 +00:00
|
|
|
impl EarlyLintPass for UnusedImportBraces {
|
2019-02-08 11:35:41 +00:00
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
2019-09-26 16:51:36 +00:00
|
|
|
if let ast::ItemKind::Use(ref use_tree) = item.kind {
|
2017-09-26 21:04:00 +00:00
|
|
|
self.check_use_tree(cx, use_tree, item);
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 22:09:57 +00:00
|
|
|
/// The `unused_allocation` lint detects unnecessary allocations that can
|
|
|
|
/// be eliminated.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// fn main() {
|
2022-11-13 13:55:04 +00:00
|
|
|
/// let a = Box::new([1, 2, 3]).len();
|
2020-09-08 22:09:57 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// When a `box` expression is immediately coerced to a reference, then
|
|
|
|
/// the allocation is unnecessary, and a reference (using `&` or `&mut`)
|
|
|
|
/// should be used instead to avoid the allocation.
|
2017-10-20 21:00:57 +00:00
|
|
|
pub(super) UNUSED_ALLOCATION,
|
2015-09-15 22:58:19 +00:00
|
|
|
Warn,
|
|
|
|
"detects unnecessary allocations that can be eliminated"
|
|
|
|
}
|
|
|
|
|
2019-04-03 14:05:40 +00:00
|
|
|
declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
|
2015-09-15 22:58:19 +00:00
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
|
|
|
|
fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
|
2019-09-26 13:39:48 +00:00
|
|
|
match e.kind {
|
2022-11-13 13:55:04 +00:00
|
|
|
hir::ExprKind::Call(path_expr, [_])
|
|
|
|
if let hir::ExprKind::Path(qpath) = &path_expr.kind
|
|
|
|
&& let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()
|
|
|
|
&& cx.tcx.is_diagnostic_item(sym::box_new, did)
|
|
|
|
=> {}
|
2016-10-09 04:08:07 +00:00
|
|
|
_ => return,
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
for adj in cx.typeck_results().expr_adjustments(e) {
|
2017-05-27 07:29:24 +00:00
|
|
|
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
2022-09-04 19:46:35 +00:00
|
|
|
match m {
|
|
|
|
adjustment::AutoBorrowMutability::Not => {
|
|
|
|
cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag);
|
|
|
|
}
|
|
|
|
adjustment::AutoBorrowMutability::Mut { .. } => {
|
|
|
|
cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag);
|
|
|
|
}
|
|
|
|
};
|
2015-09-15 22:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|