2020-03-27 21:54:52 +01:00
|
|
|
use crate::Lint;
|
2020-01-09 07:52:01 +01:00
|
|
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast as ast;
|
2020-02-29 20:37:32 +03:00
|
|
|
use rustc_ast::util::parser;
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::{ExprKind, StmtKind};
|
2020-01-11 17:02:46 +01:00
|
|
|
use rustc_ast_pretty::pprust;
|
2019-04-10 19:47:55 +02:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2020-01-09 11:18:47 +01:00
|
|
|
use rustc_errors::{pluralize, Applicability};
|
2019-11-30 02:34:18 +01:00
|
|
|
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir as hir;
|
|
|
|
use rustc_hir::def::{DefKind, Res};
|
|
|
|
use rustc_hir::def_id::DefId;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::ty::adjustment;
|
|
|
|
use rustc_middle::ty::{self, Ty};
|
2020-01-09 07:52:01 +01:00
|
|
|
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
2020-01-01 19:30:57 +01:00
|
|
|
use rustc_span::symbol::Symbol;
|
|
|
|
use rustc_span::symbol::{kw, sym};
|
2020-04-24 18:22:18 +02:00
|
|
|
use rustc_span::{BytePos, Span, DUMMY_SP};
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-08-13 23:05:01 -07:00
|
|
|
use tracing::debug;
|
2019-02-08 20:35:41 +09:00
|
|
|
|
2015-09-15 18:58:19 -04:00
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07: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 18:58:19 -04:00
|
|
|
pub UNUSED_MUST_USE,
|
|
|
|
Warn,
|
2019-07-19 00:05:23 +02:00
|
|
|
"unused result of a type flagged as `#[must_use]`",
|
2019-10-08 18:47:08 -04:00
|
|
|
report_in_external_macro
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07: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 18:58:19 -04:00
|
|
|
pub UNUSED_RESULTS,
|
|
|
|
Allow,
|
|
|
|
"unused result of an expression in a statement"
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:05:40 +02:00
|
|
|
declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
2019-09-26 17:34:50 +01:00
|
|
|
let expr = match s.kind {
|
2019-01-17 09:45:02 +11:00
|
|
|
hir::StmtKind::Semi(ref expr) => &**expr,
|
2016-10-09 09:38:07 +05:30
|
|
|
_ => return,
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
|
|
|
|
2019-09-26 14:39:48 +01:00
|
|
|
if let hir::ExprKind::Ret(..) = expr.kind {
|
2015-09-15 18:58:19 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
let ty = cx.typeck_results().expr_ty(&expr);
|
2019-09-19 15:13:40 +08:00
|
|
|
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
|
2017-08-07 17:20:19 -07:00
|
|
|
|
|
|
|
let mut fn_warned = false;
|
2017-09-22 15:45:47 -07:00
|
|
|
let mut op_warned = false;
|
2019-09-26 14:39:48 +01:00
|
|
|
let maybe_def_id = match expr.kind {
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Call(ref callee, _) => {
|
2019-09-26 14:39:48 +01:00
|
|
|
match callee.kind {
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Path(ref qpath) => {
|
2020-06-26 05:55:23 +03:00
|
|
|
match cx.qpath_res(qpath, callee.hir_id) {
|
2020-04-16 17:38:52 -07:00
|
|
|
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
|
2019-04-20 19:36:05 +03:00
|
|
|
// `Res::Local` if it was a closure, for which we
|
2018-10-11 23:10:37 -07:00
|
|
|
// do not currently support must-use linting
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
2018-03-10 16:23:28 -08:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
|
|
|
_ => None,
|
2018-03-10 16:23:28 -08:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2020-07-17 08:47:04 +00:00
|
|
|
hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
2018-03-10 16:23:28 -08:00
|
|
|
};
|
2019-04-20 19:46:19 +03:00
|
|
|
if let Some(def_id) = maybe_def_id {
|
2019-05-23 22:56:23 +01:00
|
|
|
fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
|
2018-11-03 19:23:05 +00:00
|
|
|
} else if type_permits_lack_of_use {
|
2018-10-08 21:08:01 +01: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-10 16:23:28 -08:00
|
|
|
}
|
2018-10-08 21:08:01 +01:00
|
|
|
|
2019-09-26 14:39:48 +01:00
|
|
|
let must_use_op = match expr.kind {
|
2018-03-10 16:23:28 -08: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
|
2019-12-22 17:42:04 -05:00
|
|
|
hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
|
|
|
|
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
|
|
|
|
| hir::BinOpKind::Rem => Some("arithmetic operation"),
|
|
|
|
hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
|
|
|
|
hir::BinOpKind::BitXor
|
|
|
|
| hir::BinOpKind::BitAnd
|
|
|
|
| hir::BinOpKind::BitOr
|
|
|
|
| hir::BinOpKind::Shl
|
|
|
|
| hir::BinOpKind::Shr => Some("bitwise operation"),
|
2018-03-10 16:23:28 -08:00
|
|
|
},
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Unary(..) => Some("unary operation"),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
2018-03-10 16:23:28 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(must_use_op) = must_use_op {
|
2020-02-03 19:57:45 +10:00
|
|
|
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
|
|
|
|
lint.build(&format!("unused {} that must be used", must_use_op)).emit()
|
|
|
|
});
|
2018-03-10 16:23:28 -08:00
|
|
|
op_warned = true;
|
2017-08-07 17:20:19 -07:00
|
|
|
}
|
2018-03-10 16:23:28 -08:00
|
|
|
|
2018-11-03 19:23:05 +00:00
|
|
|
if !(type_permits_lack_of_use || fn_warned || op_warned) {
|
2020-02-02 19:41:14 +10:00
|
|
|
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
2019-05-23 22:56:23 +01:00
|
|
|
// Returns whether an error has been emitted (and thus another does not need to be later).
|
2019-05-27 20:11:15 +01:00
|
|
|
fn check_must_use_ty<'tcx>(
|
2020-06-25 23:41:36 +03:00
|
|
|
cx: &LateContext<'tcx>,
|
2019-05-27 20:11:15 +01:00
|
|
|
ty: Ty<'tcx>,
|
2019-11-30 15:08:22 +01:00
|
|
|
expr: &hir::Expr<'_>,
|
2019-05-23 22:56:23 +01:00
|
|
|
span: Span,
|
2019-06-29 16:23:15 +01:00
|
|
|
descr_pre: &str,
|
|
|
|
descr_post: &str,
|
2019-09-19 15:13:40 +08:00
|
|
|
plural_len: usize,
|
2019-05-23 22:56:23 +01:00
|
|
|
) -> bool {
|
2020-03-16 18:51:55 +01:00
|
|
|
if ty.is_unit()
|
|
|
|
|| cx.tcx.is_ty_uninhabited_from(
|
2020-03-18 20:27:59 +02:00
|
|
|
cx.tcx.parent_module(expr.hir_id).to_def_id(),
|
2020-03-16 18:51:55 +01:00
|
|
|
ty,
|
|
|
|
cx.param_env,
|
|
|
|
)
|
2019-05-27 20:11:15 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:10:24 -05:00
|
|
|
let plural_suffix = pluralize!(plural_len);
|
2019-06-29 16:23:15 +01:00
|
|
|
|
2020-08-03 00:49:11 +02:00
|
|
|
match *ty.kind() {
|
2019-06-29 13:53:46 +01:00
|
|
|
ty::Adt(..) if ty.is_box() => {
|
|
|
|
let boxed_ty = ty.boxed_ty();
|
2019-06-29 16:23:15 +01:00
|
|
|
let descr_pre = &format!("{}boxed ", descr_pre);
|
2019-09-19 15:13:40 +08:00
|
|
|
check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
|
2019-06-29 13:53:46 +01:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
ty::Adt(def, _) => check_must_use_def(cx, def.did, span, descr_pre, descr_post),
|
2019-05-23 22:56:23 +01:00
|
|
|
ty::Opaque(def, _) => {
|
|
|
|
let mut has_emitted = false;
|
2019-10-18 03:14:57 +03:00
|
|
|
for (predicate, _) in cx.tcx.predicates_of(def).predicates {
|
2020-06-18 20:33:52 +02:00
|
|
|
// We only look at the `DefId`, so it is safe to skip the binder here.
|
2020-07-09 00:35:55 +02:00
|
|
|
if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
|
|
|
|
predicate.skip_binders()
|
2020-05-11 22:06:41 +02:00
|
|
|
{
|
2020-06-18 20:33:52 +02:00
|
|
|
let def_id = poly_trait_predicate.trait_ref.def_id;
|
2019-12-22 17:42:04 -05:00
|
|
|
let descr_pre =
|
|
|
|
&format!("{}implementer{} of ", descr_pre, plural_suffix,);
|
2019-06-29 16:23:15 +01:00
|
|
|
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
|
2019-05-23 22:56:23 +01:00
|
|
|
has_emitted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
has_emitted
|
|
|
|
}
|
|
|
|
ty::Dynamic(binder, _) => {
|
|
|
|
let mut has_emitted = false;
|
|
|
|
for predicate in binder.skip_binder().iter() {
|
|
|
|
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
|
|
|
|
let def_id = trait_ref.def_id;
|
2019-12-22 17:42:04 -05:00
|
|
|
let descr_post =
|
|
|
|
&format!(" trait object{}{}", plural_suffix, descr_post,);
|
2019-06-29 16:23:15 +01:00
|
|
|
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
|
2019-05-23 22:56:23 +01:00
|
|
|
has_emitted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
has_emitted
|
|
|
|
}
|
|
|
|
ty::Tuple(ref tys) => {
|
2019-05-27 16:48:43 +01:00
|
|
|
let mut has_emitted = false;
|
2019-09-26 14:39:48 +01:00
|
|
|
let spans = if let hir::ExprKind::Tup(comps) = &expr.kind {
|
2019-05-27 16:48:43 +01:00
|
|
|
debug_assert_eq!(comps.len(), tys.len());
|
|
|
|
comps.iter().map(|e| e.span).collect()
|
|
|
|
} else {
|
|
|
|
vec![]
|
|
|
|
};
|
|
|
|
for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
|
2019-06-29 16:23:15 +01:00
|
|
|
let descr_post = &format!(" in tuple element {}", i);
|
2019-05-28 20:12:48 +01:00
|
|
|
let span = *spans.get(i).unwrap_or(&span);
|
2019-12-22 17:42:04 -05:00
|
|
|
if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural_len)
|
|
|
|
{
|
2019-05-27 16:48:43 +01:00
|
|
|
has_emitted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
has_emitted
|
2019-05-23 22:56:23 +01:00
|
|
|
}
|
2019-03-26 00:13:09 +01:00
|
|
|
ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
|
2019-06-29 16:23:15 +01:00
|
|
|
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
|
|
|
Some(n) if n != 0 => {
|
2019-12-22 17:42:04 -05:00
|
|
|
let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
|
2019-09-19 15:13:40 +08:00
|
|
|
check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1)
|
2019-06-29 16:23:15 +01:00
|
|
|
}
|
|
|
|
// Otherwise, we don't lint, to avoid false positives.
|
|
|
|
_ => false,
|
2019-12-22 17:42:04 -05:00
|
|
|
},
|
2020-07-28 00:00:00 +00:00
|
|
|
ty::Closure(..) => {
|
|
|
|
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
|
|
|
|
let mut err = lint.build(&format!(
|
|
|
|
"unused {}closure{}{} that must be used",
|
|
|
|
descr_pre, plural_suffix, descr_post,
|
|
|
|
));
|
|
|
|
err.note("closures are lazy and do nothing unless called");
|
|
|
|
err.emit();
|
|
|
|
});
|
|
|
|
true
|
|
|
|
}
|
|
|
|
ty::Generator(..) => {
|
|
|
|
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
|
|
|
|
let mut err = lint.build(&format!(
|
|
|
|
"unused {}generator{}{} that must be used",
|
|
|
|
descr_pre, plural_suffix, descr_post,
|
|
|
|
));
|
|
|
|
err.note("generators are lazy and do nothing unless resumed");
|
|
|
|
err.emit();
|
|
|
|
});
|
|
|
|
true
|
|
|
|
}
|
2019-05-23 22:56:23 +01:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns whether an error has been emitted (and thus another does not need to be later).
|
2020-02-06 01:27:46 +10:00
|
|
|
// FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
|
|
|
|
// would make calling it a big awkward. Could also take String (so args are moved), but
|
|
|
|
// this would still require a copy into the format string, which would only be executed
|
|
|
|
// when needed.
|
2019-05-23 22:56:23 +01:00
|
|
|
fn check_must_use_def(
|
2020-06-25 23:41:36 +03:00
|
|
|
cx: &LateContext<'_>,
|
2018-11-03 20:24:24 +00:00
|
|
|
def_id: DefId,
|
2019-05-23 22:56:23 +01:00
|
|
|
span: Span,
|
2018-11-03 20:24:24 +00:00
|
|
|
descr_pre_path: &str,
|
|
|
|
descr_post_path: &str,
|
|
|
|
) -> bool {
|
2017-06-20 04:36:56 +09:00
|
|
|
for attr in cx.tcx.get_attrs(def_id).iter() {
|
2020-07-30 11:27:50 +10:00
|
|
|
if cx.sess().check_name(attr, sym::must_use) {
|
2020-01-31 22:24:57 +10:00
|
|
|
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
|
|
|
|
let msg = format!(
|
|
|
|
"unused {}`{}`{} that must be used",
|
|
|
|
descr_pre_path,
|
|
|
|
cx.tcx.def_path_str(def_id),
|
|
|
|
descr_post_path
|
|
|
|
);
|
|
|
|
let mut err = lint.build(&msg);
|
|
|
|
// check for #[must_use = "..."]
|
|
|
|
if let Some(note) = attr.value_str() {
|
|
|
|
err.note(¬e.as_str());
|
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
});
|
2015-09-15 18:58:19 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07: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 18:58:19 -04:00
|
|
|
pub PATH_STATEMENTS,
|
|
|
|
Warn,
|
|
|
|
"path statements with no effect"
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:05:40 +02:00
|
|
|
declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for PathStatements {
|
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
2020-08-02 16:30:09 +02:00
|
|
|
if let hir::StmtKind::Semi(expr) = s.kind {
|
2019-09-26 14:39:48 +01:00
|
|
|
if let hir::ExprKind::Path(_) = expr.kind {
|
2020-02-03 19:57:45 +10:00
|
|
|
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
|
2020-08-02 16:30:09 +02:00
|
|
|
let ty = cx.typeck_results().expr_ty(expr);
|
|
|
|
if ty.needs_drop(cx.tcx, cx.param_env) {
|
|
|
|
let mut lint = lint.build("path statement drops value");
|
|
|
|
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
|
|
|
|
lint.span_suggestion(
|
|
|
|
s.span,
|
|
|
|
"use `drop` to clarify the intent",
|
|
|
|
format!("drop({});", snippet),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
lint.span_help(s.span, "use `drop` to clarify the intent");
|
|
|
|
}
|
|
|
|
lint.emit()
|
|
|
|
} else {
|
|
|
|
lint.build("path statement with no effect").emit()
|
|
|
|
}
|
2020-02-03 19:57:45 +10:00
|
|
|
});
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-10 19:47:55 +02:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedAttributes {
|
|
|
|
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UnusedAttributes {
|
|
|
|
pub fn new() -> Self {
|
2019-12-22 17:42:04 -05:00
|
|
|
UnusedAttributes { builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP }
|
2019-04-10 19:47:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for UnusedAttributes {
|
|
|
|
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
2016-08-19 18:58:14 -07:00
|
|
|
debug!("checking attribute: {:?}", attr);
|
2019-04-10 19:47:55 +02:00
|
|
|
|
2019-12-07 21:28:29 +03:00
|
|
|
if attr.is_doc_comment() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-10 19:47:55 +02:00
|
|
|
let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
|
|
|
|
|
|
|
|
if let Some(&&(name, ty, ..)) = attr_info {
|
2020-07-07 11:12:44 -04:00
|
|
|
if let AttributeType::AssumedUsed = ty {
|
|
|
|
debug!("{:?} is AssumedUsed", name);
|
2020-03-22 13:36:56 +01:00
|
|
|
return;
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 11:27:50 +10:00
|
|
|
if !cx.sess().is_attr_used(attr) {
|
2019-07-19 00:05:23 +02:00
|
|
|
debug!("emitting warning for: {:?}", attr);
|
2020-02-03 19:57:45 +10:00
|
|
|
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
|
|
|
lint.build("unused attribute").emit()
|
|
|
|
});
|
2015-09-15 18:58:19 -04:00
|
|
|
// Is it a builtin attribute that must be used at the crate level?
|
2019-11-12 21:22:16 +03:00
|
|
|
if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
|
2020-02-02 19:41:14 +10:00
|
|
|
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
|
|
|
let msg = match attr.style {
|
|
|
|
ast::AttrStyle::Outer => {
|
|
|
|
"crate-level attribute should be an inner attribute: add an exclamation \
|
|
|
|
mark: `#![foo]`"
|
|
|
|
}
|
|
|
|
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
|
|
|
};
|
|
|
|
lint.build(msg).emit()
|
|
|
|
});
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
2016-08-19 18:58:14 -07:00
|
|
|
} else {
|
|
|
|
debug!("Attr was used: {:?}", attr);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum UnusedDelimsCtx {
|
|
|
|
FunctionArg,
|
|
|
|
MethodArg,
|
|
|
|
AssignedValue,
|
|
|
|
IfCond,
|
|
|
|
WhileCond,
|
2020-03-31 18:42:54 +02:00
|
|
|
ForIterExpr,
|
|
|
|
MatchScrutineeExpr,
|
2020-03-27 21:54:52 +01:00
|
|
|
ReturnValue,
|
|
|
|
BlockRetValue,
|
2020-03-31 18:42:54 +02:00
|
|
|
LetScrutineeExpr,
|
2020-03-27 21:54:52 +01:00
|
|
|
ArrayLenExpr,
|
|
|
|
AnonConst,
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
impl From<UnusedDelimsCtx> for &'static str {
|
|
|
|
fn from(ctx: UnusedDelimsCtx) -> &'static str {
|
|
|
|
match ctx {
|
|
|
|
UnusedDelimsCtx::FunctionArg => "function argument",
|
|
|
|
UnusedDelimsCtx::MethodArg => "method argument",
|
|
|
|
UnusedDelimsCtx::AssignedValue => "assigned value",
|
|
|
|
UnusedDelimsCtx::IfCond => "`if` condition",
|
|
|
|
UnusedDelimsCtx::WhileCond => "`while` condition",
|
2020-03-31 18:42:54 +02:00
|
|
|
UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
|
|
|
|
UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
|
2020-03-27 21:54:52 +01:00
|
|
|
UnusedDelimsCtx::ReturnValue => "`return` value",
|
|
|
|
UnusedDelimsCtx::BlockRetValue => "block return value",
|
2020-03-31 18:42:54 +02:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
|
2020-03-27 21:54:52 +01:00
|
|
|
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
/// Used by both `UnusedParens` and `UnusedBraces` to prevent code duplication.
|
|
|
|
trait UnusedDelimLint {
|
|
|
|
const DELIM_STR: &'static str;
|
|
|
|
|
2020-04-04 22:40:31 +02: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 21:54:52 +01: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>,
|
|
|
|
);
|
|
|
|
|
|
|
|
fn is_expr_delims_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
|
2020-05-05 01:55:03 +02:00
|
|
|
// Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
|
2020-05-06 01:50:55 +02:00
|
|
|
let lhs_needs_parens = {
|
|
|
|
let mut innermost = inner;
|
|
|
|
loop {
|
|
|
|
if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind {
|
|
|
|
innermost = lhs;
|
|
|
|
if !rustc_ast::util::classify::expr_requires_semi_to_be_stmt(innermost) {
|
|
|
|
break true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break false;
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2020-05-05 01:55:03 +02:00
|
|
|
};
|
2020-05-06 01:50:55 +02:00
|
|
|
|
2020-05-05 01:55:03 +02:00
|
|
|
lhs_needs_parens
|
|
|
|
|| (followed_by_block
|
|
|
|
&& match inner.kind {
|
2020-08-03 01:31:21 +09:00
|
|
|
ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true,
|
2020-05-05 01:55:03 +02:00
|
|
|
_ => parser::contains_exterior_struct_lit(&inner),
|
|
|
|
})
|
2019-08-03 01:46:09 +08:00
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
fn emit_unused_delims_expr(
|
2019-12-22 17:42:04 -05:00
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
2020-03-27 21:54:52 +01:00
|
|
|
ctx: UnusedDelimsCtx,
|
2019-12-22 17:42:04 -05:00
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>,
|
|
|
|
) {
|
2020-03-27 21:54:52 +01:00
|
|
|
let expr_text = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) {
|
|
|
|
snippet
|
|
|
|
} else {
|
|
|
|
pprust::expr_to_string(value)
|
|
|
|
};
|
|
|
|
let keep_space = (
|
|
|
|
left_pos.map(|s| s >= value.span.lo()).unwrap_or(false),
|
|
|
|
right_pos.map(|s| s <= value.span.hi()).unwrap_or(false),
|
|
|
|
);
|
|
|
|
self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
2018-10-01 22:32:26 -07:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
fn emit_unused_delims(
|
2019-09-03 15:33:30 +02:00
|
|
|
&self,
|
2019-12-22 17:42:04 -05:00
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
span: Span,
|
|
|
|
pattern: &str,
|
|
|
|
msg: &str,
|
|
|
|
keep_space: (bool, bool),
|
|
|
|
) {
|
2020-04-24 18:22:18 +02:00
|
|
|
// FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
|
|
|
|
// properly.
|
|
|
|
if span == DUMMY_SP {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
cx.struct_span_lint(self.lint(), span, |lint| {
|
|
|
|
let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg);
|
2020-01-31 22:24:57 +10:00
|
|
|
let mut err = lint.build(&span_msg);
|
|
|
|
let mut ate_left_paren = false;
|
|
|
|
let mut ate_right_paren = false;
|
2020-08-10 12:04:51 +02:00
|
|
|
let parens_removed = pattern
|
|
|
|
.trim_matches(|c| match c {
|
|
|
|
'(' | '{' => {
|
|
|
|
if ate_left_paren {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
ate_left_paren = true;
|
|
|
|
true
|
|
|
|
}
|
2020-01-31 22:24:57 +10:00
|
|
|
}
|
2020-08-10 12:04:51 +02:00
|
|
|
')' | '}' => {
|
|
|
|
if ate_right_paren {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
ate_right_paren = true;
|
|
|
|
true
|
|
|
|
}
|
2020-01-31 22:24:57 +10:00
|
|
|
}
|
2020-08-10 12:04:51 +02:00
|
|
|
_ => false,
|
|
|
|
})
|
|
|
|
.trim();
|
2019-07-31 22:56:12 +08:00
|
|
|
|
2020-01-31 22:24:57 +10:00
|
|
|
let replace = {
|
|
|
|
let mut replace = if keep_space.0 {
|
|
|
|
let mut s = String::from(" ");
|
|
|
|
s.push_str(parens_removed);
|
|
|
|
s
|
|
|
|
} else {
|
|
|
|
String::from(parens_removed)
|
|
|
|
};
|
2019-08-03 01:46:09 +08:00
|
|
|
|
2020-01-31 22:24:57 +10:00
|
|
|
if keep_space.1 {
|
|
|
|
replace.push(' ');
|
|
|
|
}
|
|
|
|
replace
|
|
|
|
};
|
2019-07-31 22:56:12 +08:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
let suggestion = format!("remove these {}", Self::DELIM_STR);
|
|
|
|
|
|
|
|
err.span_suggestion_short(span, &suggestion, replace, Applicability::MachineApplicable);
|
2020-01-31 22:24:57 +10:00
|
|
|
err.emit();
|
|
|
|
});
|
2018-10-04 09:36:55 -07:00
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::ExprKind::*;
|
2020-03-27 21:54:52 +01:00
|
|
|
let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
|
2020-04-04 22:40:31 +02:00
|
|
|
// Do not lint `unused_braces` in `if let` expressions.
|
|
|
|
If(ref cond, ref block, ..)
|
|
|
|
if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
|
|
|
{
|
2019-12-31 20:15:40 +03:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(2);
|
2019-08-03 01:46:09 +08:00
|
|
|
let right = block.span.lo();
|
2020-03-27 21:54:52 +01:00
|
|
|
(cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
|
2019-08-03 01:46:09 +08:00
|
|
|
}
|
|
|
|
|
2020-08-03 12:18:10 +09:00
|
|
|
// Do not lint `unused_braces` in `while let` expressions.
|
|
|
|
While(ref cond, ref block, ..)
|
|
|
|
if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
|
|
|
{
|
2019-12-31 20:15:40 +03:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(5);
|
2019-08-03 01:46:09 +08:00
|
|
|
let right = block.span.lo();
|
2020-03-27 21:54:52 +01:00
|
|
|
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-08-03 01:46:09 +08:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
ForLoop(_, ref cond, ref block, ..) => {
|
2020-03-31 18:42:54 +02:00
|
|
|
(cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
|
2019-08-03 01:46:09 +08:00
|
|
|
}
|
|
|
|
|
2020-04-04 22:40:31 +02:00
|
|
|
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
2019-12-31 20:15:40 +03:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(5);
|
2020-03-31 18:42:54 +02:00
|
|
|
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
|
2019-08-03 01:46:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret(Some(ref value)) => {
|
2019-12-31 20:15:40 +03:00
|
|
|
let left = e.span.lo() + rustc_span::BytePos(3);
|
2020-03-27 21:54:52 +01:00
|
|
|
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
|
2019-08-03 01:46:09 +08:00
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
Assign(_, ref value, _) | AssignOp(.., ref value) => {
|
|
|
|
(value, UnusedDelimsCtx::AssignedValue, false, None, None)
|
|
|
|
}
|
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-30 17:13:05 -08:00
|
|
|
// either function/method call, or something this lint doesn't care about
|
|
|
|
ref call_or_other => {
|
2020-03-27 21:54:52 +01:00
|
|
|
let (args_to_check, ctx) = match *call_or_other {
|
|
|
|
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
|
|
|
|
// first "argument" is self (which sometimes needs delims)
|
2020-06-09 15:34:23 -04:00
|
|
|
MethodCall(_, ref args, _) => (&args[1..], 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-30 17:13:05 -08:00
|
|
|
// actual catch-all arm
|
2018-10-05 19:09:14 -07:00
|
|
|
_ => {
|
|
|
|
return;
|
|
|
|
}
|
2018-10-01 23:15:22 +02: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-30 17:13:05 -08: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 23:56:42 +03:00
|
|
|
if e.span.ctxt().outer_expn_data().call_site.from_expansion() {
|
2019-08-11 03:00:05 +03: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-30 17:13:05 -08:00
|
|
|
}
|
|
|
|
for arg in args_to_check {
|
2020-03-27 21:54:52 +01:00
|
|
|
self.check_unused_delims_expr(cx, arg, ctx, false, None, None);
|
2017-12-23 19:28:33 -08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
2020-03-27 21:54:52 +01:00
|
|
|
self.check_unused_delims_expr(cx, &value, ctx, followed_by_block, left_pos, right_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
match s.kind {
|
2020-04-04 22:40:31 +02:00
|
|
|
StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
2020-03-27 21:54:52 +01:00
|
|
|
if let Some(ref value) = local.init {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&value,
|
|
|
|
UnusedDelimsCtx::AssignedValue,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
StmtKind::Expr(ref expr) => {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&expr,
|
|
|
|
UnusedDelimsCtx::BlockRetValue,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
|
|
|
use ast::ItemKind::*;
|
|
|
|
|
|
|
|
if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
|
|
|
UnusedDelimsCtx::AssignedValue,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07:00
|
|
|
/// The `unused_parens` lint detects `if`, `match`, `while` and `return`
|
|
|
|
/// with parentheses; they do not need them.
|
|
|
|
///
|
|
|
|
/// ### Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// if(true) {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{produces}}
|
|
|
|
///
|
|
|
|
/// ### Explanation
|
|
|
|
///
|
|
|
|
/// The parenthesis are not needed, and should be removed. This is the
|
|
|
|
/// preferred style for writing these expressions.
|
2020-03-27 21:54:52 +01:00
|
|
|
pub(super) UNUSED_PARENS,
|
|
|
|
Warn,
|
|
|
|
"`if`, `match`, `while` and `return` do not need parentheses"
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
|
|
|
|
|
|
|
|
impl UnusedDelimLint for UnusedParens {
|
|
|
|
const DELIM_STR: &'static str = "parentheses";
|
|
|
|
|
2020-04-04 22:40:31 +02:00
|
|
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
|
|
|
|
|
2020-03-27 21:54:52 +01: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>,
|
|
|
|
) {
|
|
|
|
match value.kind {
|
|
|
|
ast::ExprKind::Paren(ref inner) => {
|
|
|
|
if !Self::is_expr_delims_necessary(inner, followed_by_block)
|
|
|
|
&& value.attrs.is_empty()
|
|
|
|
&& !value.span.from_expansion()
|
|
|
|
{
|
|
|
|
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprKind::Let(_, ref expr) => {
|
|
|
|
// FIXME(#60336): Properly handle `let true = (false && true)`
|
|
|
|
// actually needing the parenthesis.
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
2020-03-31 18:42:54 +02:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr,
|
2020-03-27 21:54:52 +01:00
|
|
|
followed_by_block,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UnusedParens {
|
|
|
|
fn check_unused_parens_pat(
|
|
|
|
&self,
|
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Pat,
|
|
|
|
avoid_or: bool,
|
|
|
|
avoid_mut: bool,
|
|
|
|
) {
|
|
|
|
use ast::{BindingMode, Mutability, PatKind};
|
|
|
|
|
|
|
|
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:
|
|
|
|
PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return,
|
|
|
|
// Otherwise proceed with linting.
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
let pattern_text =
|
|
|
|
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) {
|
|
|
|
snippet
|
|
|
|
} else {
|
|
|
|
pprust::pat_to_string(value)
|
|
|
|
};
|
|
|
|
self.emit_unused_delims(cx, value.span, &pattern_text, "pattern", (false, false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedParens {
|
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
|
|
|
if let ExprKind::Let(ref pat, ..) | ExprKind::ForLoop(ref pat, ..) = e.kind {
|
|
|
|
self.check_unused_parens_pat(cx, pat, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
<Self as UnusedDelimLint>::check_expr(self, cx, e)
|
2018-10-01 22:32:26 -07:00
|
|
|
}
|
|
|
|
|
2019-04-21 17:09:30 +03:00
|
|
|
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
|
2019-12-22 17:42:04 -05:00
|
|
|
use ast::{Mutability, PatKind::*};
|
2019-09-26 16:18:31 +01:00
|
|
|
match &p.kind {
|
2019-09-03 15:33:30 +02: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 15:03:11 +01:00
|
|
|
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
2019-09-03 15:33:30 +02:00
|
|
|
// These are list-like patterns; parens can always be removed.
|
|
|
|
TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
|
|
|
self.check_unused_parens_pat(cx, p, false, false);
|
|
|
|
},
|
|
|
|
Struct(_, fps, _) => for f in fps {
|
|
|
|
self.check_unused_parens_pat(cx, &f.pat, false, false);
|
|
|
|
},
|
|
|
|
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
|
|
|
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
|
|
|
|
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
|
|
|
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
2019-12-16 17:28:40 +01:00
|
|
|
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
|
2018-10-05 19:09:14 -07:00
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
|
|
|
|
self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
|
|
|
|
}
|
2020-01-23 00:42:35 -05:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
if let StmtKind::Local(ref local) = s.kind {
|
|
|
|
self.check_unused_parens_pat(cx, &local.pat, false, false);
|
2018-10-01 23:15:22 +02:00
|
|
|
}
|
2020-03-27 21:54:52 +01:00
|
|
|
|
|
|
|
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
2019-09-03 15:33:30 +02:00
|
|
|
|
|
|
|
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
|
|
|
|
self.check_unused_parens_pat(cx, ¶m.pat, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
|
2019-09-05 09:17:19 +02:00
|
|
|
self.check_unused_parens_pat(cx, &arm.pat, false, false);
|
2019-09-03 15:33:30 +02:00
|
|
|
}
|
2019-10-04 01:56:57 -04:00
|
|
|
|
|
|
|
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
|
|
|
if let &ast::TyKind::Paren(ref r) = &ty.kind {
|
|
|
|
match &r.kind {
|
|
|
|
&ast::TyKind::TraitObject(..) => {}
|
|
|
|
&ast::TyKind::ImplTrait(_, ref bounds) if bounds.len() > 1 => {}
|
2020-03-27 21:54:52 +01:00
|
|
|
&ast::TyKind::Array(_, ref len) => {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&len.value,
|
|
|
|
UnusedDelimsCtx::ArrayLenExpr,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
2019-10-04 01:56:57 -04:00
|
|
|
_ => {
|
2019-12-22 17:42:04 -05:00
|
|
|
let pattern_text =
|
|
|
|
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(ty.span) {
|
2019-10-04 01:56:57 -04:00
|
|
|
snippet
|
|
|
|
} else {
|
|
|
|
pprust::ty_to_string(ty)
|
|
|
|
};
|
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
self.emit_unused_delims(cx, ty.span, &pattern_text, "type", (false, false));
|
2019-10-04 01:56:57 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-01 18:30:52 -05:00
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
2020-03-27 21:54:52 +01:00
|
|
|
<Self as UnusedDelimLint>::check_item(self, cx, item)
|
|
|
|
}
|
|
|
|
}
|
2020-02-01 18:30:52 -05:00
|
|
|
|
2020-03-27 21:54:52 +01:00
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07: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 21:54:52 +01:00
|
|
|
pub(super) UNUSED_BRACES,
|
|
|
|
Warn,
|
2020-03-31 18:42:54 +02:00
|
|
|
"unnecessary braces around an expression"
|
2020-03-27 21:54:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
|
|
|
|
|
|
|
|
impl UnusedDelimLint for UnusedBraces {
|
|
|
|
const DELIM_STR: &'static str = "braces";
|
|
|
|
|
2020-04-04 22:40:31 +02:00
|
|
|
const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
|
|
|
|
|
2020-03-27 21:54:52 +01: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>,
|
|
|
|
) {
|
|
|
|
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
|
|
|
|
// (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
|
|
|
|
//
|
|
|
|
// 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 {
|
|
|
|
if !Self::is_expr_delims_necessary(expr, followed_by_block)
|
|
|
|
&& (ctx != UnusedDelimsCtx::AnonConst
|
|
|
|
|| matches!(expr.kind, ast::ExprKind::Lit(_)))
|
|
|
|
// array length expressions are checked during `check_anon_const` and `check_ty`,
|
|
|
|
// once as `ArrayLenExpr` and once as `AnonConst`.
|
|
|
|
//
|
|
|
|
// As we do not want to lint this twice, we do not emit an error for
|
|
|
|
// `ArrayLenExpr` if `AnonConst` would do the same.
|
|
|
|
&& (ctx != UnusedDelimsCtx::ArrayLenExpr
|
|
|
|
|| !matches!(expr.kind, ast::ExprKind::Lit(_)))
|
|
|
|
&& !cx.sess().source_map().is_multiline(value.span)
|
|
|
|
&& value.attrs.is_empty()
|
|
|
|
&& !value.span.from_expansion()
|
|
|
|
{
|
|
|
|
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprKind::Let(_, ref expr) => {
|
|
|
|
// FIXME(#60336): Properly handle `let true = (false && true)`
|
|
|
|
// actually needing the parenthesis.
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
expr,
|
2020-03-31 18:42:54 +02:00
|
|
|
UnusedDelimsCtx::LetScrutineeExpr,
|
2020-03-27 21:54:52 +01:00
|
|
|
followed_by_block,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedBraces {
|
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
|
|
|
<Self as UnusedDelimLint>::check_expr(self, cx, e)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
|
|
|
|
self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
|
|
|
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
|
|
|
if let &ast::TyKind::Paren(ref r) = &ty.kind {
|
|
|
|
if let ast::TyKind::Array(_, ref len) = r.kind {
|
|
|
|
self.check_unused_delims_expr(
|
|
|
|
cx,
|
|
|
|
&len.value,
|
|
|
|
UnusedDelimsCtx::ArrayLenExpr,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
}
|
2020-02-01 18:30:52 -05:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 21:54:52 +01:00
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
|
|
|
<Self as UnusedDelimLint>::check_item(self, cx, item)
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07: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 18:58:19 -04:00
|
|
|
UNUSED_IMPORT_BRACES,
|
|
|
|
Allow,
|
|
|
|
"unnecessary braces around an imported item"
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:05:40 +02:00
|
|
|
declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2017-09-26 23:04:00 +02:00
|
|
|
impl UnusedImportBraces {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
|
2017-09-26 23:04:00 +02:00
|
|
|
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
|
|
|
// Recursively check nested UseTrees
|
|
|
|
for &(ref tree, _) in items {
|
|
|
|
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 21:10:12 +01:00
|
|
|
let node_name = match items[0].0.kind {
|
2018-06-13 11:44:06 -05:00
|
|
|
ast::UseTreeKind::Simple(rename, ..) => {
|
2018-03-19 01:21:30 +03:00
|
|
|
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
|
2019-05-11 17:41:37 +03:00
|
|
|
if orig_ident.name == kw::SelfLower {
|
2017-09-26 23:04:00 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-09-14 21:10:12 +01:00
|
|
|
rename.unwrap_or(orig_ident).name
|
2017-09-26 23:04:00 +02:00
|
|
|
}
|
2019-09-14 21:10:12 +01:00
|
|
|
ast::UseTreeKind::Glob => Symbol::intern("*"),
|
|
|
|
ast::UseTreeKind::Nested(_) => return,
|
|
|
|
};
|
2017-09-26 23:04:00 +02:00
|
|
|
|
2020-02-03 19:57:45 +10:00
|
|
|
cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
|
|
|
|
lint.build(&format!("braces around {} is unnecessary", node_name)).emit()
|
|
|
|
});
|
2017-09-26 23:04:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-24 06:11:31 +02:00
|
|
|
impl EarlyLintPass for UnusedImportBraces {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
2019-09-26 17:51:36 +01:00
|
|
|
if let ast::ItemKind::Use(ref use_tree) = item.kind {
|
2017-09-26 23:04:00 +02:00
|
|
|
self.check_use_tree(cx, use_tree, item);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2020-09-08 15:09:57 -07:00
|
|
|
/// The `unused_allocation` lint detects unnecessary allocations that can
|
|
|
|
/// be eliminated.
|
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// #![feature(box_syntax)]
|
|
|
|
/// fn main() {
|
|
|
|
/// let a = (box [1,2,3]).len();
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// {{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-21 00:00:57 +03:00
|
|
|
pub(super) UNUSED_ALLOCATION,
|
2015-09-15 18:58:19 -04:00
|
|
|
Warn,
|
|
|
|
"detects unnecessary allocations that can be eliminated"
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:05:40 +02:00
|
|
|
declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
|
|
|
|
fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
|
2019-09-26 14:39:48 +01:00
|
|
|
match e.kind {
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Box(_) => {}
|
2016-10-09 09:38:07 +05:30
|
|
|
_ => return,
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
for adj in cx.typeck_results().expr_adjustments(e) {
|
2017-05-27 10:29:24 +03:00
|
|
|
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
2020-02-02 19:41:14 +10:00
|
|
|
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
|
|
|
|
let msg = match m {
|
|
|
|
adjustment::AutoBorrowMutability::Not => {
|
|
|
|
"unnecessary allocation, use `&` instead"
|
|
|
|
}
|
|
|
|
adjustment::AutoBorrowMutability::Mut { .. } => {
|
|
|
|
"unnecessary allocation, use `&mut` instead"
|
|
|
|
}
|
|
|
|
};
|
|
|
|
lint.build(msg).emit()
|
|
|
|
});
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|