2019-04-20 19:36:05 +03:00
|
|
|
use rustc::hir::def::{Res, DefKind};
|
2017-06-20 04:36:56 +09:00
|
|
|
use rustc::hir::def_id::DefId;
|
2019-02-08 20:35:41 +09:00
|
|
|
use rustc::lint;
|
2019-05-23 22:56:31 +01:00
|
|
|
use rustc::ty::{self, Ty};
|
2016-03-22 17:30:57 +02:00
|
|
|
use rustc::ty::adjustment;
|
2019-04-10 19:47:55 +02:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2015-09-15 18:58:19 -04:00
|
|
|
use lint::{LateContext, EarlyContext, LintContext, LintArray};
|
|
|
|
use lint::{LintPass, EarlyLintPass, LateLintPass};
|
|
|
|
|
|
|
|
use syntax::ast;
|
2016-08-23 03:54:53 +00:00
|
|
|
use syntax::attr;
|
2018-08-01 20:30:04 -07:00
|
|
|
use syntax::errors::Applicability;
|
2019-04-10 19:47:55 +02:00
|
|
|
use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
2017-09-29 23:50:34 -07:00
|
|
|
use syntax::print::pprust;
|
2019-05-11 17:41:37 +03:00
|
|
|
use syntax::symbol::{kw, sym};
|
2019-04-10 19:47:55 +02:00
|
|
|
use syntax::symbol::Symbol;
|
2017-07-20 16:53:56 -04:00
|
|
|
use syntax::util::parser;
|
2019-08-03 01:46:09 +08:00
|
|
|
use syntax_pos::{Span, BytePos};
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2016-03-29 08:50:44 +03:00
|
|
|
use rustc::hir;
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2019-02-08 20:35:41 +09:00
|
|
|
use log::debug;
|
|
|
|
|
2015-09-15 18:58:19 -04:00
|
|
|
declare_lint! {
|
|
|
|
pub UNUSED_MUST_USE,
|
|
|
|
Warn,
|
2019-07-19 00:05:23 +02:00
|
|
|
"unused result of a type flagged as `#[must_use]`",
|
2018-11-01 03:32:45 +00:00
|
|
|
report_in_external_macro: true
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
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
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) {
|
2015-09-15 18:58:19 -04:00
|
|
|
let expr = match s.node {
|
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
|
|
|
};
|
|
|
|
|
2018-07-11 20:05:29 +08:00
|
|
|
if let hir::ExprKind::Ret(..) = expr.node {
|
2015-09-15 18:58:19 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-23 22:56:23 +01:00
|
|
|
let ty = cx.tables.expr_ty(&expr);
|
2019-06-29 16:23:15 +01:00
|
|
|
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false);
|
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-04-20 19:46:19 +03:00
|
|
|
let maybe_def_id = match expr.node {
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Call(ref callee, _) => {
|
2018-03-10 16:23:28 -08:00
|
|
|
match callee.node {
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Path(ref qpath) => {
|
2019-04-20 19:36:05 +03:00
|
|
|
match cx.tables.qpath_res(qpath, callee.hir_id) {
|
|
|
|
Res::Def(DefKind::Fn, def_id)
|
|
|
|
| Res::Def(DefKind::Method, def_id) => Some(def_id),
|
|
|
|
// `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
|
|
|
|
_ => None
|
2018-03-10 16:23:28 -08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
},
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::MethodCall(..) => {
|
2019-04-20 19:46:19 +03:00
|
|
|
cx.tables.type_dependent_def_id(expr.hir_id)
|
2018-03-10 16:23:28 -08:00
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
};
|
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
|
|
|
|
2018-03-10 16:23:28 -08:00
|
|
|
let must_use_op = match expr.node {
|
|
|
|
// 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 20:05:29 +08:00
|
|
|
hir::ExprKind::Binary(bin_op, ..) => {
|
2018-03-10 16:23:28 -08:00
|
|
|
match bin_op.node {
|
2018-07-12 08:20:31 +08:00
|
|
|
hir::BinOpKind::Eq |
|
|
|
|
hir::BinOpKind::Lt |
|
|
|
|
hir::BinOpKind::Le |
|
|
|
|
hir::BinOpKind::Ne |
|
|
|
|
hir::BinOpKind::Ge |
|
|
|
|
hir::BinOpKind::Gt => {
|
2018-03-10 16:23:28 -08:00
|
|
|
Some("comparison")
|
|
|
|
},
|
2018-07-12 08:20:31 +08:00
|
|
|
hir::BinOpKind::Add |
|
|
|
|
hir::BinOpKind::Sub |
|
|
|
|
hir::BinOpKind::Div |
|
|
|
|
hir::BinOpKind::Mul |
|
|
|
|
hir::BinOpKind::Rem => {
|
2018-03-10 16:23:28 -08:00
|
|
|
Some("arithmetic operation")
|
|
|
|
},
|
2018-07-11 18:44:53 +08:00
|
|
|
hir::BinOpKind::And | hir::BinOpKind::Or => {
|
2018-03-10 16:23:28 -08:00
|
|
|
Some("logical operation")
|
|
|
|
},
|
2018-07-12 08:20:31 +08:00
|
|
|
hir::BinOpKind::BitXor |
|
|
|
|
hir::BinOpKind::BitAnd |
|
|
|
|
hir::BinOpKind::BitOr |
|
|
|
|
hir::BinOpKind::Shl |
|
|
|
|
hir::BinOpKind::Shr => {
|
2018-03-10 16:23:28 -08:00
|
|
|
Some("bitwise operation")
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2018-07-11 20:05:29 +08:00
|
|
|
hir::ExprKind::Unary(..) => Some("unary operation"),
|
2018-03-10 16:23:28 -08:00
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(must_use_op) = must_use_op {
|
|
|
|
cx.span_lint(UNUSED_MUST_USE, expr.span,
|
2018-10-08 20:36:50 +01:00
|
|
|
&format!("unused {} that must be used", must_use_op));
|
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) {
|
2015-09-15 18:58:19 -04:00
|
|
|
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
|
|
|
|
}
|
|
|
|
|
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>(
|
|
|
|
cx: &LateContext<'_, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
2019-05-27 16:48:43 +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,
|
|
|
|
plural: bool,
|
2019-05-23 22:56:23 +01:00
|
|
|
) -> bool {
|
2019-05-27 20:11:15 +01:00
|
|
|
if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(
|
2019-06-14 18:58:55 +02:00
|
|
|
cx.tcx.hir().get_module_parent(expr.hir_id), ty)
|
2019-05-27 20:11:15 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-29 16:23:15 +01:00
|
|
|
let plural_suffix = if plural { "s" } else { "" };
|
|
|
|
|
2019-05-23 22:56:23 +01:00
|
|
|
match ty.sty {
|
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);
|
|
|
|
check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural)
|
2019-06-29 13:53:46 +01:00
|
|
|
}
|
|
|
|
ty::Adt(def, _) => {
|
2019-06-29 16:23:15 +01:00
|
|
|
check_must_use_def(cx, def.did, span, descr_pre, descr_post)
|
2019-06-29 13:53:46 +01:00
|
|
|
}
|
2019-05-23 22:56:23 +01:00
|
|
|
ty::Opaque(def, _) => {
|
|
|
|
let mut has_emitted = false;
|
|
|
|
for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
|
|
|
|
if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
|
|
|
|
let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
|
|
|
|
let def_id = trait_ref.def_id;
|
2019-06-29 16:23:15 +01:00
|
|
|
let descr_pre = &format!(
|
|
|
|
"{}implementer{} of ",
|
|
|
|
descr_pre,
|
|
|
|
plural_suffix,
|
|
|
|
);
|
|
|
|
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-06-29 16:23:15 +01:00
|
|
|
let descr_post = &format!(
|
|
|
|
" trait object{}{}",
|
|
|
|
plural_suffix,
|
|
|
|
descr_post,
|
|
|
|
);
|
|
|
|
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;
|
|
|
|
let spans = if let hir::ExprKind::Tup(comps) = &expr.node {
|
|
|
|
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-06-29 16:23:15 +01:00
|
|
|
if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) {
|
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 => {
|
|
|
|
let descr_pre = &format!(
|
|
|
|
"{}array{} of ",
|
|
|
|
descr_pre,
|
|
|
|
plural_suffix,
|
|
|
|
);
|
|
|
|
check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true)
|
|
|
|
}
|
|
|
|
// Otherwise, we don't lint, to avoid false positives.
|
|
|
|
_ => false,
|
|
|
|
}
|
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).
|
|
|
|
fn check_must_use_def(
|
2019-02-08 20:35:41 +09: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() {
|
2019-05-08 13:21:18 +10:00
|
|
|
if attr.check_name(sym::must_use) {
|
2018-11-03 20:24:24 +00:00
|
|
|
let msg = format!("unused {}`{}`{} that must be used",
|
2018-12-19 12:31:35 +02:00
|
|
|
descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path);
|
2019-05-23 22:56:23 +01:00
|
|
|
let mut err = cx.struct_span_lint(UNUSED_MUST_USE, span, &msg);
|
2018-05-03 21:01:57 -07:00
|
|
|
// check for #[must_use = "..."]
|
|
|
|
if let Some(note) = attr.value_str() {
|
|
|
|
err.note(¬e.as_str());
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
2018-05-03 21:01:57 -07:00
|
|
|
err.emit();
|
2015-09-15 18:58:19 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
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
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) {
|
2019-01-17 09:45:02 +11:00
|
|
|
if let hir::StmtKind::Semi(ref expr) = s.node {
|
2018-07-11 18:54:37 +08:00
|
|
|
if let hir::ExprKind::Path(_) = expr.node {
|
2016-10-09 09:38:07 +05:30
|
|
|
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2015-09-29 16:44:26 +01:00
|
|
|
pub UNUSED_ATTRIBUTES,
|
2015-09-15 18:58:19 -04:00
|
|
|
Warn,
|
|
|
|
"detects attributes that were not used by the compiler"
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
UnusedAttributes {
|
|
|
|
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
2019-02-08 20:35:41 +09:00
|
|
|
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
|
|
|
|
|
|
|
let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
|
|
|
|
|
|
|
|
if let Some(&&(name, ty, ..)) = attr_info {
|
2015-09-15 18:58:19 -04:00
|
|
|
match ty {
|
2019-04-10 19:47:55 +02:00
|
|
|
AttributeType::Whitelisted => {
|
2016-08-19 18:58:14 -07:00
|
|
|
debug!("{:?} is Whitelisted", name);
|
2019-04-10 19:47:55 +02:00
|
|
|
return;
|
2016-10-09 09:38:07 +05:30
|
|
|
}
|
|
|
|
_ => (),
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
|
2019-05-08 13:21:18 +10:00
|
|
|
for &(name, ty) in plugin_attributes.iter() {
|
|
|
|
if ty == AttributeType::Whitelisted && attr.check_name(name) {
|
2016-08-19 18:58:14 -07:00
|
|
|
debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
|
2015-09-15 18:58:19 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 14:17:47 +03:00
|
|
|
let name = attr.name_or_empty();
|
2015-09-15 18:58:19 -04:00
|
|
|
if !attr::is_used(attr) {
|
2019-07-19 00:05:23 +02:00
|
|
|
debug!("emitting warning for: {:?}", attr);
|
2015-09-15 18:58:19 -04:00
|
|
|
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
|
|
|
|
// Is it a builtin attribute that must be used at the crate level?
|
2019-04-10 19:47:55 +02:00
|
|
|
let known_crate = attr_info.map(|&&(_, ty, ..)| {
|
|
|
|
ty == AttributeType::CrateLevel
|
|
|
|
}).unwrap_or(false);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
2018-10-08 21:08:01 +01:00
|
|
|
// Has a plugin registered this attribute as one that must be used at
|
2015-09-15 18:58:19 -04:00
|
|
|
// the crate level?
|
|
|
|
let plugin_crate = plugin_attributes.iter()
|
2019-05-08 14:33:06 +10:00
|
|
|
.find(|&&(x, t)| name == x && AttributeType::CrateLevel == t)
|
2016-10-09 09:38:07 +05:30
|
|
|
.is_some();
|
|
|
|
if known_crate || plugin_crate {
|
2016-11-14 12:00:25 +00:00
|
|
|
let msg = match attr.style {
|
2016-10-09 09:38:07 +05:30
|
|
|
ast::AttrStyle::Outer => {
|
|
|
|
"crate-level attribute should be an inner attribute: add an exclamation \
|
2019-07-19 00:05:23 +02:00
|
|
|
mark: `#![foo]`"
|
2016-10-09 09:38:07 +05:30
|
|
|
}
|
|
|
|
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
|
|
|
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
|
|
|
|
}
|
2016-08-19 18:58:14 -07:00
|
|
|
} else {
|
|
|
|
debug!("Attr was used: {:?}", attr);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
2017-10-21 00:00:57 +03:00
|
|
|
pub(super) UNUSED_PARENS,
|
2015-09-15 18:58:19 -04:00
|
|
|
Warn,
|
|
|
|
"`if`, `match`, `while` and `return` do not need parentheses"
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:05:40 +02:00
|
|
|
declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
|
2015-09-15 18:58:19 -04:00
|
|
|
|
|
|
|
impl UnusedParens {
|
2019-08-03 01:46:09 +08:00
|
|
|
|
|
|
|
fn is_expr_parens_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
|
|
|
|
followed_by_block && match inner.node {
|
|
|
|
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
|
|
|
|
_ => parser::contains_exterior_struct_lit(&inner),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-01 22:32:26 -07:00
|
|
|
fn check_unused_parens_expr(&self,
|
2019-08-03 01:46:09 +08:00
|
|
|
cx: &EarlyContext<'_>,
|
|
|
|
value: &ast::Expr,
|
|
|
|
msg: &str,
|
|
|
|
followed_by_block: bool,
|
|
|
|
left_pos: Option<BytePos>,
|
|
|
|
right_pos: Option<BytePos>) {
|
2019-05-15 16:03:43 +02:00
|
|
|
match value.node {
|
|
|
|
ast::ExprKind::Paren(ref inner) => {
|
2019-08-03 01:46:09 +08:00
|
|
|
if !Self::is_expr_parens_necessary(inner, followed_by_block) {
|
2019-05-15 16:03:43 +02:00
|
|
|
let expr_text = if let Ok(snippet) = cx.sess().source_map()
|
|
|
|
.span_to_snippet(value.span) {
|
|
|
|
snippet
|
|
|
|
} else {
|
|
|
|
pprust::expr_to_string(value)
|
|
|
|
};
|
2019-08-03 01:46:09 +08:00
|
|
|
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::remove_outer_parens(cx, value.span, &expr_text, msg, keep_space);
|
2019-05-15 16:03:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprKind::Let(_, ref expr) => {
|
|
|
|
// FIXME(#60336): Properly handle `let true = (false && true)`
|
|
|
|
// actually needing the parenthesis.
|
2019-08-03 02:17:20 +08:00
|
|
|
self.check_unused_parens_expr(
|
|
|
|
cx, expr,
|
|
|
|
"`let` head expression",
|
|
|
|
followed_by_block,
|
|
|
|
None, None
|
|
|
|
);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
2019-05-15 16:03:43 +02:00
|
|
|
_ => {}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
2018-10-01 22:32:26 -07:00
|
|
|
|
|
|
|
fn check_unused_parens_pat(&self,
|
2019-02-08 20:35:41 +09:00
|
|
|
cx: &EarlyContext<'_>,
|
2018-10-01 22:32:26 -07:00
|
|
|
value: &ast::Pat,
|
2018-10-05 19:09:14 -07:00
|
|
|
msg: &str) {
|
2018-10-01 22:32:26 -07:00
|
|
|
if let ast::PatKind::Paren(_) = value.node {
|
2018-10-16 21:36:02 -07:00
|
|
|
let pattern_text = if let Ok(snippet) = cx.sess().source_map()
|
|
|
|
.span_to_snippet(value.span) {
|
|
|
|
snippet
|
|
|
|
} else {
|
|
|
|
pprust::pat_to_string(value)
|
|
|
|
};
|
2019-08-03 01:46:09 +08:00
|
|
|
Self::remove_outer_parens(cx, value.span, &pattern_text, msg, (false, false));
|
2018-10-01 22:32:26 -07:00
|
|
|
}
|
|
|
|
}
|
2018-10-04 09:36:55 -07:00
|
|
|
|
2019-08-03 02:17:20 +08:00
|
|
|
fn remove_outer_parens(cx: &EarlyContext<'_>,
|
|
|
|
span: Span,
|
|
|
|
pattern: &str,
|
|
|
|
msg: &str,
|
|
|
|
keep_space: (bool, bool)) {
|
2018-10-04 09:36:55 -07:00
|
|
|
let span_msg = format!("unnecessary parentheses around {}", msg);
|
|
|
|
let mut err = cx.struct_span_lint(UNUSED_PARENS, span, &span_msg);
|
|
|
|
let mut ate_left_paren = false;
|
|
|
|
let mut ate_right_paren = false;
|
|
|
|
let parens_removed = pattern
|
|
|
|
.trim_matches(|c| {
|
|
|
|
match c {
|
|
|
|
'(' => {
|
|
|
|
if ate_left_paren {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
ate_left_paren = true;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
')' => {
|
|
|
|
if ate_right_paren {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
ate_right_paren = true;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => false,
|
|
|
|
}
|
2019-07-31 22:56:12 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
let replace = {
|
2019-08-03 01:46:09 +08:00
|
|
|
let mut replace = if keep_space.0 {
|
|
|
|
let mut s = String::from(" ");
|
|
|
|
s.push_str(parens_removed);
|
|
|
|
s
|
|
|
|
} else {
|
|
|
|
String::from(parens_removed)
|
|
|
|
};
|
|
|
|
|
|
|
|
if keep_space.1 {
|
|
|
|
replace.push(' ');
|
|
|
|
}
|
2019-07-31 22:56:12 +08:00
|
|
|
replace
|
|
|
|
};
|
|
|
|
|
2019-01-25 16:03:27 -05:00
|
|
|
err.span_suggestion_short(
|
|
|
|
span,
|
|
|
|
"remove these parentheses",
|
2019-07-31 22:56:12 +08:00
|
|
|
replace,
|
2019-01-25 16:03:27 -05:00
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
2018-10-04 09:36:55 -07:00
|
|
|
err.emit();
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedParens {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
2016-02-08 16:05:05 +01:00
|
|
|
use syntax::ast::ExprKind::*;
|
2019-08-03 01:46:09 +08:00
|
|
|
let (value, msg, followed_by_block, left_pos, right_pos) = match e.node {
|
|
|
|
If(ref cond, ref block, ..) => {
|
|
|
|
let left = e.span.lo() + syntax_pos::BytePos(2);
|
|
|
|
let right = block.span.lo();
|
|
|
|
(cond, "`if` condition", true, Some(left), Some(right))
|
|
|
|
}
|
|
|
|
|
|
|
|
While(ref cond, ref block, ..) => {
|
|
|
|
let left = e.span.lo() + syntax_pos::BytePos(5);
|
|
|
|
let right = block.span.lo();
|
|
|
|
(cond, "`while` condition", true, Some(left), Some(right))
|
|
|
|
},
|
|
|
|
|
|
|
|
ForLoop(_, ref cond, ref block, ..) => {
|
|
|
|
(cond, "`for` head expression", true, None, Some(block.span.lo()))
|
|
|
|
}
|
|
|
|
|
|
|
|
Match(ref head, _) => {
|
|
|
|
let left = e.span.lo() + syntax_pos::BytePos(5);
|
|
|
|
(head, "`match` head expression", true, Some(left), None)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ret(Some(ref value)) => {
|
|
|
|
let left = e.span.lo() + syntax_pos::BytePos(3);
|
|
|
|
(value, "`return` value", false, Some(left), None)
|
|
|
|
}
|
|
|
|
|
|
|
|
Assign(_, ref value) => (value, "assigned value", false, None, None),
|
|
|
|
AssignOp(.., ref value) => (value, "assigned value", 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 => {
|
2018-10-01 23:15:22 +02:00
|
|
|
let (args_to_check, call_kind) = match *call_or_other {
|
|
|
|
Call(_, ref args) => (&args[..], "function"),
|
|
|
|
// first "argument" is self (which sometimes needs parens)
|
|
|
|
MethodCall(_, ref args) => (&args[1..], "method"),
|
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-05-27 13:52:11 +10:00
|
|
|
if e.span.ctxt().outer_expn_info()
|
|
|
|
.map_or(false, |info| info.call_site.ctxt().outer_expn_info().is_some()) {
|
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
|
|
|
return;
|
|
|
|
}
|
|
|
|
let msg = format!("{} argument", call_kind);
|
|
|
|
for arg in args_to_check {
|
2019-08-03 01:46:09 +08:00
|
|
|
self.check_unused_parens_expr(cx, arg, &msg, false, None, None);
|
2017-12-23 19:28:33 -08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
2019-08-03 01:46:09 +08:00
|
|
|
self.check_unused_parens_expr(cx, &value, msg, followed_by_block, left_pos, right_pos);
|
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) {
|
2018-10-06 19:48:04 -07:00
|
|
|
use ast::PatKind::{Paren, Range};
|
2018-10-09 17:37:45 -07:00
|
|
|
// 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
|
2018-11-10 18:08:50 +00:00
|
|
|
// unnecessary parens they serve a purpose of readability.
|
2018-10-06 19:48:04 -07:00
|
|
|
if let Paren(ref pat) = p.node {
|
|
|
|
match pat.node {
|
|
|
|
Range(..) => {}
|
|
|
|
_ => self.check_unused_parens_pat(cx, &p, "pattern")
|
|
|
|
}
|
2018-10-05 19:09:14 -07:00
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
2018-10-01 23:15:22 +02:00
|
|
|
if let ast::StmtKind::Local(ref local) = s.node {
|
|
|
|
if let Some(ref value) = local.init {
|
2019-08-03 01:46:09 +08:00
|
|
|
self.check_unused_parens_expr(cx, &value, "assigned value", false, None, None);
|
2016-10-09 09:38:07 +05:30
|
|
|
}
|
2018-10-01 23:15:22 +02:00
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
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
|
|
|
|
let node_ident;
|
|
|
|
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;
|
|
|
|
}
|
2018-10-01 23:15:22 +02:00
|
|
|
node_ident = rename.unwrap_or(orig_ident);
|
2017-09-26 23:04:00 +02:00
|
|
|
}
|
|
|
|
ast::UseTreeKind::Glob => {
|
|
|
|
node_ident = ast::Ident::from_str("*");
|
|
|
|
}
|
|
|
|
ast::UseTreeKind::Nested(_) => {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let msg = format!("braces around {} is unnecessary", node_ident.name);
|
|
|
|
cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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) {
|
2017-09-26 23:04:00 +02:00
|
|
|
if let ast::ItemKind::Use(ref use_tree) = item.node {
|
|
|
|
self.check_use_tree(cx, use_tree, item);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
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
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
2019-02-08 20:35:41 +09:00
|
|
|
fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) {
|
2015-09-15 18:58:19 -04:00
|
|
|
match e.node {
|
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
|
|
|
}
|
|
|
|
|
2017-05-27 10:29:24 +03:00
|
|
|
for adj in cx.tables.expr_adjustments(e) {
|
|
|
|
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
|
|
|
let msg = match m {
|
2018-01-23 13:31:11 +01:00
|
|
|
adjustment::AutoBorrowMutability::Immutable =>
|
2019-07-19 00:05:23 +02:00
|
|
|
"unnecessary allocation, use `&` instead",
|
2018-01-23 13:31:11 +01:00
|
|
|
adjustment::AutoBorrowMutability::Mutable { .. }=>
|
2019-07-19 00:05:23 +02:00
|
|
|
"unnecessary allocation, use `&mut` instead"
|
2017-05-27 10:29:24 +03:00
|
|
|
};
|
|
|
|
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|