2015-09-15 18:58:19 -04:00
|
|
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2018-03-10 14:26:33 -08:00
|
|
|
use rustc::hir::def::Def;
|
2017-06-20 04:36:56 +09:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-03-22 17:30:57 +02:00
|
|
|
use rustc::ty;
|
|
|
|
use rustc::ty::adjustment;
|
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;
|
2016-11-08 08:30:26 +10:30
|
|
|
use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
|
2017-09-29 23:50:34 -07:00
|
|
|
use syntax::print::pprust;
|
2017-09-15 12:49:10 -07:00
|
|
|
use syntax::symbol::keywords;
|
2017-07-20 16:53:56 -04:00
|
|
|
use syntax::util::parser;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax_pos::Span;
|
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
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
pub UNUSED_MUST_USE,
|
|
|
|
Warn,
|
|
|
|
"unused result of a type flagged as #[must_use]"
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
pub UNUSED_RESULTS,
|
|
|
|
Allow,
|
|
|
|
"unused result of an expression in a statement"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedResults;
|
|
|
|
|
|
|
|
impl LintPass for UnusedResults {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
2016-12-07 13:56:36 +01:00
|
|
|
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
|
2015-09-15 18:58:19 -04:00
|
|
|
let expr = match s.node {
|
|
|
|
hir::StmtSemi(ref expr, _) => &**expr,
|
2016-10-09 09:38:07 +05:30
|
|
|
_ => return,
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
if let hir::ExprRet(..) = expr.node {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:54:24 +02:00
|
|
|
let t = cx.tables.expr_ty(&expr);
|
2017-08-07 17:20:19 -07:00
|
|
|
let ty_warned = match t.sty {
|
2018-01-21 13:33:21 +08:00
|
|
|
ty::TyTuple(ref tys) if tys.is_empty() => return,
|
2017-08-11 13:43:33 -07:00
|
|
|
ty::TyNever => return,
|
2017-08-11 21:52:16 -07:00
|
|
|
ty::TyAdt(def, _) => {
|
|
|
|
if def.variants.is_empty() {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
check_must_use(cx, def.did, s.span, "")
|
|
|
|
}
|
|
|
|
},
|
2015-09-15 18:58:19 -04:00
|
|
|
_ => 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;
|
2018-03-10 16:23:28 -08:00
|
|
|
let maybe_def = match expr.node {
|
|
|
|
hir::ExprCall(ref callee, _) => {
|
|
|
|
match callee.node {
|
|
|
|
hir::ExprPath(ref qpath) => {
|
|
|
|
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
|
|
|
if let Def::Fn(_) = def {
|
|
|
|
Some(def)
|
|
|
|
} else { // `Def::Local` if it was a closure, for which we
|
|
|
|
None // do not currently support must-use linting
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
},
|
|
|
|
hir::ExprMethodCall(..) => {
|
|
|
|
cx.tables.type_dependent_defs().get(expr.hir_id).cloned()
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
if let Some(def) = maybe_def {
|
|
|
|
let def_id = def.def_id();
|
|
|
|
fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
|
|
|
|
}
|
|
|
|
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
|
|
|
|
hir::ExprBinary(bin_op, ..) => {
|
|
|
|
match bin_op.node {
|
|
|
|
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => {
|
|
|
|
Some("comparison")
|
|
|
|
},
|
|
|
|
hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => {
|
|
|
|
Some("arithmetic operation")
|
|
|
|
},
|
|
|
|
hir::BiAnd | hir::BiOr => {
|
|
|
|
Some("logical operation")
|
|
|
|
},
|
|
|
|
hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => {
|
|
|
|
Some("bitwise operation")
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
hir::ExprUnary(..) => Some("unary operation"),
|
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(must_use_op) = must_use_op {
|
|
|
|
cx.span_lint(UNUSED_MUST_USE, expr.span,
|
|
|
|
&format!("unused {} which must be used", must_use_op));
|
|
|
|
op_warned = true;
|
2017-08-07 17:20:19 -07:00
|
|
|
}
|
2018-03-10 16:23:28 -08:00
|
|
|
|
2017-09-22 15:45:47 -07:00
|
|
|
if !(ty_warned || fn_warned || op_warned) {
|
2015-09-15 18:58:19 -04:00
|
|
|
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
|
|
|
|
}
|
|
|
|
|
2017-08-07 17:20:19 -07:00
|
|
|
fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str) -> bool {
|
2017-06-20 04:36:56 +09:00
|
|
|
for attr in cx.tcx.get_attrs(def_id).iter() {
|
2015-09-15 18:58:19 -04:00
|
|
|
if attr.check_name("must_use") {
|
2017-08-07 17:20:19 -07:00
|
|
|
let mut msg = format!("unused {}`{}` which must be used",
|
|
|
|
describe_path, cx.tcx.item_path_str(def_id));
|
2015-09-15 18:58:19 -04:00
|
|
|
// check for #[must_use="..."]
|
2016-07-03 14:38:37 -07:00
|
|
|
if let Some(s) = attr.value_str() {
|
|
|
|
msg.push_str(": ");
|
2016-11-16 10:52:37 +00:00
|
|
|
msg.push_str(&s.as_str());
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
cx.span_lint(UNUSED_MUST_USE, sp, &msg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
pub PATH_STATEMENTS,
|
|
|
|
Warn,
|
|
|
|
"path statements with no effect"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct PathStatements;
|
|
|
|
|
|
|
|
impl LintPass for PathStatements {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(PATH_STATEMENTS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
|
2016-12-07 13:56:36 +01:00
|
|
|
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
|
2015-10-28 01:08:46 +09:00
|
|
|
if let hir::StmtSemi(ref expr, _) = s.node {
|
2016-10-27 05:17:42 +03:00
|
|
|
if let hir::ExprPath(_) = 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"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedAttributes;
|
|
|
|
|
|
|
|
impl LintPass for UnusedAttributes {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(UNUSED_ATTRIBUTES)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
2016-12-07 13:56:36 +01:00
|
|
|
fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
|
2016-08-19 18:58:14 -07:00
|
|
|
debug!("checking attribute: {:?}", attr);
|
2017-03-03 09:23:59 +00:00
|
|
|
let name = unwrap_or!(attr.name(), return);
|
2016-08-19 18:58:14 -07:00
|
|
|
|
2015-09-15 18:58:19 -04:00
|
|
|
// Note that check_name() marks the attribute as used if it matches.
|
2016-11-08 08:30:26 +10:30
|
|
|
for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
|
2015-09-15 18:58:19 -04:00
|
|
|
match ty {
|
|
|
|
AttributeType::Whitelisted if attr.check_name(name) => {
|
2016-08-19 18:58:14 -07:00
|
|
|
debug!("{:?} is Whitelisted", name);
|
2015-09-15 18:58:19 -04:00
|
|
|
break;
|
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();
|
|
|
|
for &(ref name, ty) in plugin_attributes.iter() {
|
2016-02-09 21:39:09 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !attr::is_used(attr) {
|
2016-08-19 18:58:14 -07: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?
|
2016-11-08 08:30:26 +10:30
|
|
|
let known_crate = BUILTIN_ATTRIBUTES.iter()
|
2017-03-03 09:23:59 +00:00
|
|
|
.find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
|
2016-10-09 09:38:07 +05:30
|
|
|
.is_some();
|
2015-09-15 18:58:19 -04:00
|
|
|
|
|
|
|
// Has a plugin registered this attribute as one which must be used at
|
|
|
|
// the crate level?
|
|
|
|
let plugin_crate = plugin_attributes.iter()
|
2017-03-03 09:23:59 +00:00
|
|
|
.find(|&&(ref 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 \
|
|
|
|
mark: #![foo]"
|
|
|
|
}
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedParens;
|
|
|
|
|
|
|
|
impl UnusedParens {
|
2016-10-09 09:38:07 +05:30
|
|
|
fn check_unused_parens_core(&self,
|
|
|
|
cx: &EarlyContext,
|
|
|
|
value: &ast::Expr,
|
|
|
|
msg: &str,
|
2015-09-15 18:58:19 -04:00
|
|
|
struct_lit_needs_parens: bool) {
|
2016-02-08 16:05:05 +01:00
|
|
|
if let ast::ExprKind::Paren(ref inner) = value.node {
|
2017-07-20 16:53:56 -04:00
|
|
|
let necessary = struct_lit_needs_parens &&
|
|
|
|
parser::contains_exterior_struct_lit(&inner);
|
2015-09-15 18:58:19 -04:00
|
|
|
if !necessary {
|
2017-09-29 23:50:34 -07:00
|
|
|
let span_msg = format!("unnecessary parentheses around {}", msg);
|
|
|
|
let mut err = cx.struct_span_lint(UNUSED_PARENS,
|
|
|
|
value.span,
|
|
|
|
&span_msg);
|
2017-09-30 00:53:26 -07:00
|
|
|
// Remove exactly one pair of parentheses (rather than naïvely
|
|
|
|
// stripping all paren characters)
|
|
|
|
let mut ate_left_paren = false;
|
|
|
|
let mut ate_right_paren = false;
|
2017-09-29 23:50:34 -07:00
|
|
|
let parens_removed = pprust::expr_to_string(value)
|
2017-09-30 00:53:26 -07:00
|
|
|
.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,
|
|
|
|
}
|
|
|
|
}).to_owned();
|
2017-09-29 23:50:34 -07:00
|
|
|
err.span_suggestion_short(value.span,
|
|
|
|
"remove these parentheses",
|
|
|
|
parens_removed);
|
|
|
|
err.emit();
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LintPass for UnusedParens {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(UNUSED_PARENS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EarlyLintPass for UnusedParens {
|
|
|
|
fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
|
2016-02-08 16:05:05 +01:00
|
|
|
use syntax::ast::ExprKind::*;
|
2015-09-15 18:58:19 -04:00
|
|
|
let (value, msg, struct_lit_needs_parens) = match e.node {
|
2016-08-26 19:23:42 +03:00
|
|
|
If(ref cond, ..) => (cond, "`if` condition", true),
|
|
|
|
While(ref cond, ..) => (cond, "`while` condition", true),
|
|
|
|
IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
|
|
|
|
WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
|
|
|
|
ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
|
2016-02-08 16:05:05 +01:00
|
|
|
Match(ref head, _) => (head, "`match` head expression", true),
|
|
|
|
Ret(Some(ref value)) => (value, "`return` value", false),
|
|
|
|
Assign(_, ref value) => (value, "assigned value", false),
|
2016-08-26 19:23:42 +03:00
|
|
|
AssignOp(.., ref value) => (value, "assigned value", false),
|
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 => {
|
|
|
|
let args_to_check;
|
|
|
|
let call_kind;
|
|
|
|
match *call_or_other {
|
|
|
|
Call(_, ref args) => {
|
|
|
|
call_kind = "function";
|
|
|
|
args_to_check = &args[..];
|
|
|
|
},
|
|
|
|
MethodCall(_, ref args) => {
|
|
|
|
call_kind = "method";
|
|
|
|
// first "argument" is self (which sometimes needs parens)
|
|
|
|
args_to_check = &args[1..];
|
|
|
|
}
|
|
|
|
// actual catch-all arm
|
|
|
|
_ => { return; }
|
2017-12-23 19:28:33 -08: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)
|
|
|
|
if e.span.ctxt().outer().expn_info()
|
|
|
|
.map_or(false, |info| info.call_site.ctxt().outer()
|
|
|
|
.expn_info().is_some()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let msg = format!("{} argument", call_kind);
|
|
|
|
for arg in args_to_check {
|
|
|
|
self.check_unused_parens_core(cx, arg, &msg, false);
|
2017-12-23 19:28:33 -08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
2016-02-09 21:39:09 +01:00
|
|
|
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
|
|
|
|
let (value, msg) = match s.node {
|
2016-10-09 09:38:07 +05:30
|
|
|
ast::StmtKind::Local(ref local) => {
|
|
|
|
match local.init {
|
|
|
|
Some(ref value) => (value, "assigned value"),
|
|
|
|
None => return,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => return,
|
2015-09-15 18:58:19 -04:00
|
|
|
};
|
2016-02-09 21:39:09 +01:00
|
|
|
self.check_unused_parens_core(cx, &value, msg, false);
|
2015-09-15 18:58:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint! {
|
|
|
|
UNUSED_IMPORT_BRACES,
|
|
|
|
Allow,
|
|
|
|
"unnecessary braces around an imported item"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedImportBraces;
|
|
|
|
|
2017-09-26 23:04:00 +02:00
|
|
|
impl UnusedImportBraces {
|
|
|
|
fn check_use_tree(&self, cx: &EarlyContext, use_tree: &ast::UseTree, item: &ast::Item) {
|
|
|
|
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-03-09 18:58:44 +03:00
|
|
|
ast::UseTreeKind::Simple(rename) => {
|
2018-03-19 01:21:30 +03:00
|
|
|
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
|
2018-03-09 18:58:44 +03:00
|
|
|
if orig_ident.name == keywords::SelfValue.name() {
|
2017-09-26 23:04:00 +02:00
|
|
|
return;
|
|
|
|
} else {
|
2018-03-09 18:58:44 +03: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 18:58:19 -04:00
|
|
|
impl LintPass for UnusedImportBraces {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(UNUSED_IMPORT_BRACES)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-24 06:11:31 +02:00
|
|
|
impl EarlyLintPass for UnusedImportBraces {
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct UnusedAllocation;
|
|
|
|
|
|
|
|
impl LintPass for UnusedAllocation {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(UNUSED_ALLOCATION)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 13:14:47 +01:00
|
|
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
2016-12-07 13:56:36 +01:00
|
|
|
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
|
2015-09-15 18:58:19 -04:00
|
|
|
match e.node {
|
2015-09-24 18:00:08 +03:00
|
|
|
hir::ExprBox(_) => {}
|
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 =>
|
|
|
|
"unnecessary allocation, use & instead",
|
|
|
|
adjustment::AutoBorrowMutability::Mutable { .. }=>
|
|
|
|
"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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|