Merge pull request #1373 from Manishearth/rustup

WIP: rustup
This commit is contained in:
Martin Carton 2016-12-17 01:35:37 +01:00 committed by GitHub
commit ea0227fff7
80 changed files with 1039 additions and 798 deletions

View File

@ -1,6 +1,9 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.0.104 — 2016-12-15
* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
## 0.0.103 — 2016-11-25
* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*

View File

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.0.103"
version = "0.0.104"
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",
"Andre Bogus <bogusandre@gmail.com>",
@ -25,7 +25,7 @@ test = false
[dependencies]
# begin automatic update
clippy_lints = { version = "0.0.103", path = "clippy_lints" }
clippy_lints = { version = "0.0.104", path = "clippy_lints" }
# end automatic update
[dev-dependencies]

View File

@ -1,7 +1,7 @@
[package]
name = "clippy_lints"
# begin automatic update
version = "0.0.103"
version = "0.0.104"
# end automatic update
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",

View File

@ -59,8 +59,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprLit(ref lit) = e.node {
check_lit(cx, lit, e);
}

View File

@ -47,8 +47,8 @@ impl LintPass for Arithmetic {
}
}
impl LateLintPass for Arithmetic {
fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
if self.span.is_some() {
return;
}
@ -82,7 +82,7 @@ impl LateLintPass for Arithmetic {
}
}
fn check_expr_post(&mut self, _: &LateContext, expr: &hir::Expr) {
fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
if Some(expr.span) == self.span {
self.span = None;
}

View File

@ -55,8 +55,8 @@ impl LintPass for ArrayIndexing {
}
}
impl LateLintPass for ArrayIndexing {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
if let hir::ExprIndex(ref array, ref index) = e.node {
// Array with known size can be checked statically
let ty = cx.tcx.tables().expr_ty(array);

View File

@ -66,8 +66,8 @@ impl LintPass for AssignOps {
}
}
impl LateLintPass for AssignOps {
fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
match expr.node {
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
span_lint_and_then(cx, ASSIGN_OPS, expr.span, "assign operation detected", |db| {

View File

@ -81,8 +81,8 @@ impl LintPass for AttrPass {
}
}
impl LateLintPass for AttrPass {
fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) {
if let MetaItemKind::List(ref items) = attr.value.node {
if items.is_empty() || attr.name() != "deprecated" {
return;
@ -99,13 +99,13 @@ impl LateLintPass for AttrPass {
}
}
fn check_item(&mut self, cx: &LateContext, item: &Item) {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if is_relevant_item(cx, item) {
check_attrs(cx, item.span, &item.name, &item.attrs)
}
match item.node {
ItemExternCrate(_) |
ItemUse(_) => {
ItemUse(_, _) => {
for attr in &item.attrs {
if let MetaItemKind::List(ref lint_list) = attr.value.node {
match &*attr.name().as_str() {
@ -113,7 +113,7 @@ impl LateLintPass for AttrPass {
// whitelist `unused_imports`
for lint in lint_list {
if is_word(lint, "unused_imports") {
if let ItemUse(_) = item.node {
if let ItemUse(_, _) = item.node {
return;
}
}
@ -138,13 +138,13 @@ impl LateLintPass for AttrPass {
}
}
fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
if is_relevant_impl(cx, item) {
check_attrs(cx, item.span, &item.name, &item.attrs)
}
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
if is_relevant_trait(cx, item) {
check_attrs(cx, item.span, &item.name, &item.attrs)
}
@ -152,8 +152,8 @@ impl LateLintPass for AttrPass {
}
fn is_relevant_item(cx: &LateContext, item: &Item) -> bool {
if let ItemFn(_, _, _, _, _, ref expr) = item.node {
is_relevant_expr(cx, expr)
if let ItemFn(_, _, _, _, _, eid) = item.node {
is_relevant_expr(cx, cx.tcx.map.expr(eid))
} else {
false
}
@ -161,7 +161,7 @@ fn is_relevant_item(cx: &LateContext, item: &Item) -> bool {
fn is_relevant_impl(cx: &LateContext, item: &ImplItem) -> bool {
match item.node {
ImplItemKind::Method(_, ref expr) => is_relevant_expr(cx, expr),
ImplItemKind::Method(_, eid) => is_relevant_expr(cx, cx.tcx.map.expr(eid)),
_ => false,
}
}
@ -169,7 +169,7 @@ fn is_relevant_impl(cx: &LateContext, item: &ImplItem) -> bool {
fn is_relevant_trait(cx: &LateContext, item: &TraitItem) -> bool {
match item.node {
MethodTraitItem(_, None) => true,
MethodTraitItem(_, Some(ref expr)) => is_relevant_expr(cx, expr),
MethodTraitItem(_, Some(eid)) => is_relevant_expr(cx, cx.tcx.map.expr(eid)),
_ => false,
}
}
@ -193,8 +193,8 @@ fn is_relevant_expr(cx: &LateContext, expr: &Expr) -> bool {
ExprRet(Some(ref e)) => is_relevant_expr(cx, e),
ExprRet(None) | ExprBreak(_, None) => false,
ExprCall(ref path_expr, _) => {
if let ExprPath(..) = path_expr.node {
let fun_id = resolve_node(cx, path_expr.id).expect("function should be resolved").def_id();
if let ExprPath(ref qpath) = path_expr.node {
let fun_id = resolve_node(cx, qpath, path_expr.id).def_id();
!match_def_path(cx, fun_id, &paths::BEGIN_PANIC)
} else {
true

View File

@ -1,5 +1,5 @@
use rustc::hir::*;
use rustc::hir::def::{Def, PathResolution};
use rustc::hir::def::Def;
use rustc::lint::*;
use rustc_const_eval::lookup_const_by_id;
use syntax::ast::LitKind;
@ -79,8 +79,8 @@ impl LintPass for BitMask {
}
}
impl LateLintPass for BitMask {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprBinary(ref cmp, ref left, ref right) = e.node {
if cmp.node.is_comparison() {
if let Some(cmp_opt) = fetch_int_literal(cx, right) {
@ -245,18 +245,13 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> {
None
}
}
ExprPath(_, _) => {
{
// Important to let the borrow expire before the const lookup to avoid double
// borrowing.
let def_map = cx.tcx.def_map.borrow();
match def_map.get(&lit.id) {
Some(&PathResolution { base_def: Def::Const(def_id), .. }) => Some(def_id),
_ => None,
}
ExprPath(ref qpath) => {
let def = cx.tcx.tables().qpath_def(qpath, lit.id);
if let Def::Const(def_id) = def {
lookup_const_by_id(cx.tcx, def_id, None).and_then(|(l, _ty)| fetch_int_literal(cx, l))
} else {
None
}
.and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None))
.and_then(|(l, _ty)| fetch_int_literal(cx, l))
}
_ => None,
}

View File

@ -37,9 +37,9 @@ impl LintPass for BlackListedName {
}
}
impl LateLintPass for BlackListedName {
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
if let PatKind::Binding(_, ref ident, _) = pat.node {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlackListedName {
fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
if let PatKind::Binding(_, _, ref ident, _) = pat.node {
if self.blacklist.iter().any(|s| s == &*ident.node.as_str()) {
span_lint(cx,
BLACKLISTED_NAME,

View File

@ -1,6 +1,6 @@
use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass};
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_expr};
use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap};
use utils::*;
/// **What it does:** Checks for `if` conditions that use blocks to contain an
@ -49,13 +49,15 @@ impl LintPass for BlockInIfCondition {
}
}
struct ExVisitor<'v> {
found_block: Option<&'v Expr>,
struct ExVisitor<'a, 'tcx: 'a> {
found_block: Option<&'tcx Expr>,
cx: &'a LateContext<'a, 'tcx>,
}
impl<'v> Visitor<'v> for ExVisitor<'v> {
fn visit_expr(&mut self, expr: &'v Expr) {
if let ExprClosure(_, _, ref expr, _) = expr.node {
impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if let ExprClosure(_, _, eid, _) = expr.node {
let expr = self.cx.tcx.map.expr(eid);
if matches!(expr.node, ExprBlock(_)) {
self.found_block = Some(expr);
return;
@ -63,14 +65,17 @@ impl<'v> Visitor<'v> for ExVisitor<'v> {
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
const BRACED_EXPR_MESSAGE: &'static str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &'static str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a 'let'";
impl LateLintPass for BlockInIfCondition {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprIf(ref check, ref then, _) = expr.node {
if let ExprBlock(ref block) = check.node {
if block.rules == DefaultBlock {
@ -105,7 +110,7 @@ impl LateLintPass for BlockInIfCondition {
}
}
} else {
let mut visitor = ExVisitor { found_block: None };
let mut visitor = ExVisitor { found_block: None, cx: cx };
walk_expr(&mut visitor, check);
if let Some(block) = visitor.found_block {
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);

View File

@ -53,13 +53,15 @@ impl LintPass for NonminimalBool {
}
}
impl LateLintPass for NonminimalBool {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
NonminimalBoolVisitor(cx).visit_item(item)
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonminimalBool {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
NonminimalBoolVisitor { cx: cx }.visit_item(item)
}
}
struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);
struct NonminimalBoolVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
use quine_mc_cluskey::Bool;
struct Hir2Qmm<'a, 'tcx: 'a, 'v> {
@ -308,7 +310,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
fn bool_expr(&self, e: &Expr) {
let mut h2q = Hir2Qmm {
terminals: Vec::new(),
cx: self.0,
cx: self.cx,
};
if let Ok(expr) = h2q.run(e) {
@ -343,7 +345,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
continue 'simplified;
}
if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
span_lint_and_then(self.0,
span_lint_and_then(self.cx,
LOGIC_BUG,
e.span,
"this boolean expression contains a logic bug",
@ -353,7 +355,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
outer expression");
db.span_suggestion(e.span,
"it would look like the following",
suggest(self.0, suggestion, &h2q.terminals));
suggest(self.cx, suggestion, &h2q.terminals));
});
// don't also lint `NONMINIMAL_BOOL`
return;
@ -370,13 +372,13 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
}
}
if !improvements.is_empty() {
span_lint_and_then(self.0,
span_lint_and_then(self.cx,
NONMINIMAL_BOOL,
e.span,
"this boolean expression can be simplified",
|db| {
for suggestion in &improvements {
db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals));
db.span_suggestion(e.span, "try", suggest(self.cx, suggestion, &h2q.terminals));
}
});
}
@ -384,15 +386,15 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
}
}
impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'v Expr) {
if in_macro(self.0, e.span) {
impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr) {
if in_macro(self.cx, e.span) {
return;
}
match e.node {
ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e),
ExprUnary(UnNot, ref inner) => {
if self.0.tcx.tables.borrow().node_types[&inner.id].is_bool() {
if self.cx.tcx.tables.borrow().node_types[&inner.id].is_bool() {
self.bool_expr(e);
} else {
walk_expr(self, e);
@ -401,4 +403,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
_ => walk_expr(self, e),
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}

View File

@ -1,7 +1,7 @@
#![allow(cast_possible_truncation)]
use rustc::lint::LateContext;
use rustc::hir::def::{Def, PathResolution};
use rustc::hir::def::Def;
use rustc_const_eval::lookup_const_by_id;
use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::hir::*;
@ -10,7 +10,7 @@ use std::cmp::PartialOrd;
use std::hash::{Hash, Hasher};
use std::mem;
use std::rc::Rc;
use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy};
use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy, NodeId};
use syntax::ptr::P;
#[derive(Debug, Copy, Clone)]
@ -252,7 +252,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
/// simple constant folding: Insert an expression, get a constant or none.
fn expr(&mut self, e: &Expr) -> Option<Constant> {
match e.node {
ExprPath(_, _) => self.fetch_path(e),
ExprPath(ref qpath) => self.fetch_path(qpath, e.id),
ExprBlock(ref block) => self.block(block),
ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise),
ExprLit(ref lit) => Some(lit_to_constant(&lit.node)),
@ -285,21 +285,22 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
/// lookup a possibly constant expression from a ExprPath
fn fetch_path(&mut self, e: &Expr) -> Option<Constant> {
fn fetch_path(&mut self, qpath: &QPath, id: NodeId) -> Option<Constant> {
if let Some(lcx) = self.lcx {
let mut maybe_id = None;
if let Some(&PathResolution { base_def: Def::Const(id), .. }) = lcx.tcx.def_map.borrow().get(&e.id) {
maybe_id = Some(id);
}
// separate if lets to avoid double borrowing the def_map
if let Some(id) = maybe_id {
if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None) {
let ret = self.expr(const_expr);
if ret.is_some() {
self.needed_resolution = true;
let def = lcx.tcx.tables().qpath_def(qpath, id);
match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = Some(lcx.tcx.tables().node_id_item_substs(id)
.unwrap_or_else(|| lcx.tcx.intern_substs(&[])));
if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, def_id, substs) {
let ret = self.expr(const_expr);
if ret.is_some() {
self.needed_resolution = true;
}
return ret;
}
return ret;
}
},
_ => {},
}
}
None

View File

@ -109,8 +109,8 @@ impl LintPass for CopyAndPaste {
}
}
impl LateLintPass for CopyAndPaste {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if !in_macro(cx, expr.span) {
// skip ifs directly in else, it will be checked in the parent if
if let Some(&Expr { node: ExprIf(_, _, Some(ref else_expr)), .. }) = get_parent_expr(cx, expr) {
@ -254,7 +254,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned
bindings_impl(cx, pat, map);
}
}
PatKind::Binding(_, ref ident, ref as_pat) => {
PatKind::Binding(_, _, ref ident, ref as_pat) => {
if let Entry::Vacant(v) = map.entry(ident.node.as_str()) {
v.insert(cx.tcx.tables().pat_ty(pat));
}

View File

@ -4,7 +4,7 @@ use rustc::cfg::CFG;
use rustc::lint::*;
use rustc::ty;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_expr};
use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap};
use syntax::ast::Attribute;
use syntax::attr;
use syntax::codemap::Span;
@ -42,7 +42,7 @@ impl LintPass for CyclomaticComplexity {
}
impl CyclomaticComplexity {
fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, expr: &Expr, span: Span) {
fn check<'a, 'tcx: 'a>(&mut self, cx: &'a LateContext<'a, 'tcx>, expr: &'tcx Expr, span: Span) {
if in_macro(cx, span) {
return;
}
@ -60,7 +60,7 @@ impl CyclomaticComplexity {
divergence: 0,
short_circuits: 0,
returns: 0,
tcx: &cx.tcx,
cx: cx,
};
helper.visit_expr(expr);
let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper;
@ -90,45 +90,45 @@ impl CyclomaticComplexity {
}
}
impl LateLintPass for CyclomaticComplexity {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
if let ItemFn(_, _, _, _, _, ref expr) = item.node {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemFn(_, _, _, _, _, eid) = item.node {
if !attr::contains_name(&item.attrs, "test") {
self.check(cx, expr, item.span);
self.check(cx, cx.tcx.map.expr(eid), item.span);
}
}
}
fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
if let ImplItemKind::Method(_, ref expr) = item.node {
self.check(cx, expr, item.span);
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
if let ImplItemKind::Method(_, eid) = item.node {
self.check(cx, cx.tcx.map.expr(eid), item.span);
}
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
if let MethodTraitItem(_, Some(ref expr)) = item.node {
self.check(cx, expr, item.span);
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
if let MethodTraitItem(_, Some(eid)) = item.node {
self.check(cx, cx.tcx.map.expr(eid), item.span);
}
}
fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
}
fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
}
}
struct CCHelper<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
struct CCHelper<'a, 'tcx: 'a> {
match_arms: u64,
divergence: u64,
returns: u64,
short_circuits: u64, // && and ||
tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>,
cx: &'a LateContext<'a, 'tcx>,
}
impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> {
fn visit_expr(&mut self, e: &'a Expr) {
impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr) {
match e.node {
ExprMatch(_, ref arms, _) => {
walk_expr(self, e);
@ -139,10 +139,10 @@ impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> {
}
ExprCall(ref callee, _) => {
walk_expr(self, e);
let ty = self.tcx.tables().node_id_to_type(callee.id);
let ty = self.cx.tcx.tables().node_id_to_type(callee.id);
match ty.sty {
ty::TyFnDef(_, _, ty) |
ty::TyFnPtr(ty) if ty.sig.skip_binder().output.sty == ty::TyNever => {
ty::TyFnPtr(ty) if ty.sig.skip_binder().output().sty == ty::TyNever => {
self.divergence += 1;
}
_ => (),
@ -160,6 +160,9 @@ impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> {
_ => walk_expr(self, e),
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
}
#[cfg(feature="debugging")]

View File

@ -5,7 +5,7 @@ use rustc::ty;
use rustc::hir::*;
use syntax::codemap::Span;
use utils::paths;
use utils::{is_automatically_derived, match_path, span_lint_and_then};
use utils::{is_automatically_derived, span_lint_and_then, match_path_old};
/// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
/// explicitly.
@ -70,8 +70,8 @@ impl LintPass for Derive {
}
}
impl LateLintPass for Derive {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
let ty = cx.tcx.item_type(cx.tcx.map.local_def_id(item.id));
let is_automatically_derived = is_automatically_derived(&*item.attrs);
@ -86,10 +86,10 @@ impl LateLintPass for Derive {
}
/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>,
fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>,
hash_is_automatically_derived: bool) {
if_let_chain! {[
match_path(&trait_ref.path, &paths::HASH),
match_path_old(&trait_ref.path, &paths::HASH),
let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait()
], {
let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id);
@ -131,7 +131,7 @@ fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_re
/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
if match_path(&trait_ref.path, &paths::CLONE_TRAIT) {
if match_path_old(&trait_ref.path, &paths::CLONE_TRAIT) {
let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
let subst_ty = ty.subst(cx.tcx, parameter_environment.free_substs);

View File

@ -35,11 +35,11 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprCall(ref path, ref args) = expr.node {
if let ExprPath(None, _) = path.node {
let def_id = cx.tcx.expect_def(path.id).def_id();
if let ExprPath(ref qpath) = path.node {
let def_id = cx.tcx.tables().qpath_def(qpath, path.id).def_id();
if match_def_path(cx, def_id, &paths::DROP) {
if args.len() != 1 {
return;

View File

@ -1,5 +1,5 @@
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_expr, walk_block};
use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, NestedVisitorMap};
use rustc::lint::*;
use syntax::codemap::Span;
use utils::SpanlessEq;
@ -39,8 +39,8 @@ impl LintPass for HashMapLint {
}
}
impl LateLintPass for HashMapLint {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprIf(ref check, ref then_block, ref else_block) = expr.node {
if let ExprUnary(UnOp::UnNot, ref check) = check.node {
if let Some((ty, map, key)) = check_cond(cx, check) {
@ -111,8 +111,8 @@ struct InsertVisitor<'a, 'tcx: 'a, 'b> {
sole_expr: bool,
}
impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> {
fn visit_expr(&mut self, expr: &'v Expr) {
impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if_let_chain! {[
let ExprMethodCall(ref name, _, ref params) = expr.node,
params.len() == 3,
@ -144,4 +144,7 @@ impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> {
walk_expr(self, expr);
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}

View File

@ -36,9 +36,9 @@ impl LintPass for UnportableVariant {
}
}
impl LateLintPass for UnportableVariant {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
#[allow(cast_possible_truncation, cast_sign_loss)]
fn check_item(&mut self, cx: &LateContext, item: &Item) {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemEnum(ref def, _) = item.node {
for var in &def.variants {
let variant = &var.node;

View File

@ -1,9 +1,7 @@
//! lint on `use`ing all variants of an enum
use rustc::hir::*;
use rustc::hir::def::Def;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext};
use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray};
use syntax::ast::NodeId;
use syntax::codemap::Span;
use utils::span_lint;
@ -34,8 +32,8 @@ impl LintPass for EnumGlobUse {
}
}
impl LateLintPass for EnumGlobUse {
fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse {
fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: NodeId) {
// only check top level `use` statements
for item in &m.item_ids {
self.lint_item(cx, cx.krate.item(item.id));
@ -48,24 +46,12 @@ impl EnumGlobUse {
if item.vis == Visibility::Public {
return; // re-exports are fine
}
if let ItemUse(ref item_use) = item.node {
if let ViewPath_::ViewPathGlob(_) = item_use.node {
if let Some(def) = cx.tcx.def_map.borrow().get(&item.id) {
if let Some(node_id) = cx.tcx.map.as_local_node_id(def.full_def().def_id()) {
if let Some(NodeItem(it)) = cx.tcx.map.find(node_id) {
if let ItemEnum(..) = it.node {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
} else {
let child = cx.sess().cstore.item_children(def.full_def().def_id());
if let Some(child) = child.first() {
if let Def::Variant(..) = child.def {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
}
}
if let ItemUse(ref path, UseKind::Glob) = item.node {
// FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;`
// extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an `Enum`
//if let Def::Enum(_) = path.def {
if path.segments.last().and_then(|seg| seg.name.as_str().chars().next()).map_or(false, char::is_uppercase) {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
}

View File

@ -32,8 +32,8 @@ impl LintPass for EqOp {
}
}
impl LateLintPass for EqOp {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprBinary(ref op, ref left, ref right) = e.node {
if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
span_lint(cx,

View File

@ -60,8 +60,16 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Expr, _: Span, id: NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
_: visit::FnKind<'tcx>,
decl: &'tcx FnDecl,
body: &'tcx Expr,
_: Span,
id: NodeId,
) {
let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id);
let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env);

View File

@ -33,8 +33,8 @@ impl LintPass for EtaPass {
}
}
impl LateLintPass for EtaPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
match expr.node {
ExprCall(_, ref args) |
ExprMethodCall(_, _, ref args) => {
@ -48,7 +48,8 @@ impl LateLintPass for EtaPass {
}
fn check_closure(cx: &LateContext, expr: &Expr) {
if let ExprClosure(_, ref decl, ref ex, _) = expr.node {
if let ExprClosure(_, ref decl, eid, _) = expr.node {
let ex = cx.tcx.map.expr(eid);
if let ExprCall(ref caller, ref args) = ex.node {
if args.len() != decl.inputs.len() {
// Not the same number of arguments, there
@ -65,16 +66,16 @@ fn check_closure(cx: &LateContext, expr: &Expr) {
ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => {
if fn_ty.unsafety == Unsafety::Unsafe ||
fn_ty.sig.skip_binder().output.sty == ty::TyNever {
fn_ty.sig.skip_binder().output().sty == ty::TyNever {
return;
}
}
_ => (),
}
for (a1, a2) in decl.inputs.iter().zip(args) {
if let PatKind::Binding(_, ident, _) = a1.pat.node {
if let PatKind::Binding(_, _, ident, _) = a1.pat.node {
// XXXManishearth Should I be checking the binding mode here?
if let ExprPath(None, ref p) = a2.node {
if let ExprPath(QPath::Resolved(None, ref p)) = a2.node {
if p.segments.len() != 1 {
// If it's a proper path, it can't be a local variable
return;

View File

@ -1,5 +1,5 @@
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{Visitor, walk_expr};
use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap};
use rustc::hir::*;
use rustc::ty;
use rustc::lint::*;
@ -56,34 +56,36 @@ impl LintPass for EvalOrderDependence {
}
}
impl LateLintPass for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// Find a write to a local variable.
match expr.node {
ExprAssign(ref lhs, _) | ExprAssignOp(_, ref lhs, _) => {
if let ExprPath(None, ref path) = lhs.node {
if path.segments.len() == 1 {
let var = cx.tcx.expect_def(lhs.id).def_id();
let mut visitor = ReadVisitor {
cx: cx,
var: var,
write_expr: expr,
last_expr: expr,
};
check_for_unsequenced_reads(&mut visitor);
if let ExprPath(ref qpath) = lhs.node {
if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 {
let var = cx.tcx.tables().qpath_def(qpath, lhs.id).def_id();
let mut visitor = ReadVisitor {
cx: cx,
var: var,
write_expr: expr,
last_expr: expr,
};
check_for_unsequenced_reads(&mut visitor);
}
}
}
}
_ => {}
}
}
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
match stmt.node {
StmtExpr(ref e, _) | StmtSemi(ref e, _) => DivergenceVisitor(cx).maybe_walk_expr(e),
StmtExpr(ref e, _) | StmtSemi(ref e, _) => DivergenceVisitor { cx: cx }.maybe_walk_expr(e),
StmtDecl(ref d, _) => {
if let DeclLocal(ref local) = d.node {
if let Local { init: Some(ref e), .. } = **local {
DivergenceVisitor(cx).visit_expr(e);
DivergenceVisitor { cx: cx }.visit_expr(e);
}
}
},
@ -91,10 +93,12 @@ impl LateLintPass for EvalOrderDependence {
}
}
struct DivergenceVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);
struct DivergenceVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
fn maybe_walk_expr(&mut self, e: &Expr) {
fn maybe_walk_expr(&mut self, e: &'tcx Expr) {
match e.node {
ExprClosure(..) => {},
ExprMatch(ref e, ref arms, _) => {
@ -112,7 +116,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
}
fn report_diverging_sub_expr(&mut self, e: &Expr) {
span_lint(
self.0,
self.cx,
DIVERGING_SUB_EXPRESSION,
e.span,
"sub-expression diverges",
@ -120,25 +124,25 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for DivergenceVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'v Expr) {
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr) {
match e.node {
ExprAgain(_) |
ExprBreak(_, _) |
ExprRet(_) => self.report_diverging_sub_expr(e),
ExprCall(ref func, _) => match self.0.tcx.tables().expr_ty(func).sty {
ExprCall(ref func, _) => match self.cx.tcx.tables().expr_ty(func).sty {
ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&fn_ty.sig).output.sty {
ty::TyFnPtr(fn_ty) => if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty.sig).output().sty {
self.report_diverging_sub_expr(e);
},
_ => {},
},
ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(e.id);
let borrowed_table = self.0.tcx.tables.borrow();
let borrowed_table = self.cx.tcx.tables.borrow();
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
let result_ty = method_type.ty.fn_ret();
if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&result_ty).sty {
if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&result_ty).sty {
self.report_diverging_sub_expr(e);
}
},
@ -148,9 +152,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DivergenceVisitor<'a, 'tcx> {
}
self.maybe_walk_expr(e);
}
fn visit_block(&mut self, _: &'v Block) {
fn visit_block(&mut self, _: &'tcx Block) {
// don't continue over blocks, LateLintPass already does that
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
/// Walks up the AST from the the given write expression (`vis.write_expr`)
@ -207,7 +214,7 @@ enum StopEarly {
Stop,
}
fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEarly {
fn check_expr<'a, 'tcx>(vis: & mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly {
if expr.id == vis.last_expr.id {
return StopEarly::KeepGoing;
}
@ -256,7 +263,7 @@ fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEar
StopEarly::KeepGoing
}
fn check_stmt<'v, 't>(vis: &mut ReadVisitor<'v, 't>, stmt: &'v Stmt) -> StopEarly {
fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> StopEarly {
match stmt.node {
StmtExpr(ref expr, _) |
StmtSemi(ref expr, _) => check_expr(vis, expr),
@ -274,38 +281,40 @@ fn check_stmt<'v, 't>(vis: &mut ReadVisitor<'v, 't>, stmt: &'v Stmt) -> StopEarl
}
/// A visitor that looks for reads from a variable.
struct ReadVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>,
struct ReadVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
/// The id of the variable we're looking for.
var: DefId,
/// The expressions where the write to the variable occurred (for reporting
/// in the lint).
write_expr: &'v Expr,
write_expr: &'tcx Expr,
/// The last (highest in the AST) expression we've checked, so we know not
/// to recheck it.
last_expr: &'v Expr,
last_expr: &'tcx Expr,
}
impl<'v, 't> Visitor<'v> for ReadVisitor<'v, 't> {
fn visit_expr(&mut self, expr: &'v Expr) {
impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if expr.id == self.last_expr.id {
return;
}
match expr.node {
ExprPath(None, ref path) => {
if path.segments.len() == 1 && self.cx.tcx.expect_def(expr.id).def_id() == self.var {
if is_in_assignment_position(self.cx, expr) {
// This is a write, not a read.
} else {
span_note_and_lint(
self.cx,
EVAL_ORDER_DEPENDENCE,
expr.span,
"unsequenced read of a variable",
self.write_expr.span,
"whether read occurs before this write depends on evaluation order"
);
ExprPath(ref qpath) => {
if let QPath::Resolved(None, ref path) = *qpath {
if path.segments.len() == 1 && self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id() == self.var {
if is_in_assignment_position(self.cx, expr) {
// This is a write, not a read.
} else {
span_note_and_lint(
self.cx,
EVAL_ORDER_DEPENDENCE,
expr.span,
"unsequenced read of a variable",
self.write_expr.span,
"whether read occurs before this write depends on evaluation order"
);
}
}
}
}
@ -332,6 +341,9 @@ impl<'v, 't> Visitor<'v> for ReadVisitor<'v, 't> {
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
/// Returns true if `expr` is the LHS of an assignment, like `expr = ...`.

View File

@ -38,17 +38,16 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let Some(span) = is_expn_of(cx, expr.span, "format") {
match expr.node {
// `format!("{}", foo)` expansion
ExprCall(ref fun, ref args) => {
if_let_chain!{[
let ExprPath(..) = fun.node,
let ExprPath(ref qpath) = fun.node,
args.len() == 2,
let Some(fun) = resolve_node(cx, fun.id),
match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
match_def_path(cx, resolve_node(cx, qpath, fun.id).def_id(), &paths::FMT_ARGUMENTS_NEWV1),
// ensure the format string is `"{..}"` with only one argument and no text
check_static_str(cx, &args[0]),
// ensure the format argument is `{}` ie. Display with no fancy option
@ -129,9 +128,8 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
exprs.len() == 1,
let ExprCall(_, ref args) = exprs[0].node,
args.len() == 2,
let ExprPath(None, _) = args[1].node,
let Some(fun) = resolve_node(cx, args[1].id),
match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD),
let ExprPath(ref qpath) = args[1].node,
match_def_path(cx, resolve_node(cx, qpath, args[1].id).def_id(), &paths::DISPLAY_FMT_METHOD),
], {
let ty = walk_ptrs_ty(cx.tcx.tables().pat_ty(&pat[0]));

View File

@ -68,8 +68,16 @@ impl LintPass for Functions {
}
}
impl LateLintPass for Functions {
fn check_fn(&mut self, cx: &LateContext, kind: intravisit::FnKind, decl: &hir::FnDecl, expr: &hir::Expr, span: Span, nodeid: ast::NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
kind: intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
expr: &'tcx hir::Expr,
span: Span,
nodeid: ast::NodeId,
) {
use rustc::hir::map::Node::*;
let is_impl = if let Some(NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
@ -97,21 +105,22 @@ impl LateLintPass for Functions {
self.check_raw_ptr(cx, unsafety, decl, expr, nodeid);
}
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, ref expr) = item.node {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, eid) = item.node {
// don't lint extern functions decls, it's not their fault
if sig.abi == Abi::Rust {
self.check_arg_number(cx, &sig.decl, item.span);
}
if let Some(ref expr) = *expr {
if let Some(eid) = eid {
let expr = cx.tcx.map.expr(eid);
self.check_raw_ptr(cx, sig.unsafety, &sig.decl, expr, item.id);
}
}
}
}
impl Functions {
impl<'a, 'tcx> Functions {
fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) {
let args = decl.inputs.len() as u64;
if args > self.threshold {
@ -122,7 +131,14 @@ impl Functions {
}
}
fn check_raw_ptr(&self, cx: &LateContext, unsafety: hir::Unsafety, decl: &hir::FnDecl, expr: &hir::Expr, nodeid: ast::NodeId) {
fn check_raw_ptr(
&self,
cx: &LateContext<'a, 'tcx>,
unsafety: hir::Unsafety,
decl: &'tcx hir::FnDecl,
expr: &'tcx hir::Expr,
nodeid: ast::NodeId,
) {
if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::<HashSet<_>>();
@ -138,9 +154,9 @@ impl Functions {
}
}
fn raw_ptr_arg(cx: &LateContext, arg: &hir::Arg) -> Option<hir::def_id::DefId> {
if let (&hir::PatKind::Binding(_, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &arg.ty.node) {
cx.tcx.def_map.borrow().get(&arg.pat.id).map(|pr| pr.full_def().def_id())
fn raw_ptr_arg(_cx: &LateContext, arg: &hir::Arg) -> Option<hir::def_id::DefId> {
if let (&hir::PatKind::Binding(_, def_id, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &arg.ty.node) {
Some(def_id)
} else {
None
}
@ -151,8 +167,8 @@ struct DerefVisitor<'a, 'tcx: 'a> {
ptrs: HashSet<hir::def_id::DefId>,
}
impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'v hir::Expr) {
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
match expr.node {
hir::ExprCall(ref f, ref args) => {
let ty = self.cx.tcx.tables().expr_ty(f);
@ -179,12 +195,16 @@ impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> {
hir::intravisit::walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
intravisit::NestedVisitorMap::All(&self.cx.tcx.map)
}
}
impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> {
fn check_arg(&self, ptr: &hir::Expr) {
if let Some(def) = self.cx.tcx.def_map.borrow().get(&ptr.id) {
if self.ptrs.contains(&def.full_def().def_id()) {
if let hir::ExprPath(ref qpath) = ptr.node {
let def = self.cx.tcx.tables().qpath_def(qpath, ptr.id);
if self.ptrs.contains(&def.def_id()) {
span_lint(self.cx,
NOT_UNSAFE_PTR_ARG_DEREF,
ptr.span,

View File

@ -31,8 +31,8 @@ impl LintPass for IdentityOp {
}
}
impl LateLintPass for IdentityOp {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if in_macro(cx, e.span) {
return;
}

View File

@ -42,8 +42,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprMatch(ref op, ref arms, MatchSource::IfLetDesugar{..}) = expr.node {
@ -63,7 +63,7 @@ impl LateLintPass for Pass {
}
}
PatKind::Path(_, ref path) if match_path(path, &paths::OPTION_NONE) => {
PatKind::Path(ref path) if match_path(path, &paths::OPTION_NONE) => {
"is_none()"
}

View File

@ -59,8 +59,8 @@ impl LintPass for LenZero {
}
}
impl LateLintPass for LenZero {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if in_macro(cx, item.span) {
return;
}
@ -72,7 +72,7 @@ impl LateLintPass for LenZero {
}
}
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if in_macro(cx, expr.span) {
return;
}
@ -188,7 +188,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
if let ty::AssociatedKind::Method = item.kind {
if &*item.name.as_str() == "is_empty" {
let ty = cx.tcx.item_type(item.def_id).fn_sig().skip_binder();
ty.inputs.len() == 1
ty.inputs().len() == 1
} else {
false
}
@ -208,7 +208,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
let ty = &walk_ptrs_ty(cx.tcx.tables().expr_ty(expr));
match ty.sty {
ty::TyTrait(_) => {
ty::TyDynamic(..) => {
cx.tcx
.associated_items(ty.ty_to_def_id().expect("trait impl not found"))
.any(|item| is_is_empty(cx, &item))

View File

@ -57,27 +57,26 @@ impl LintPass for LetIfSeq {
}
}
impl LateLintPass for LetIfSeq {
fn check_block(&mut self, cx: &LateContext, block: &hir::Block) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
let mut it = block.stmts.iter().peekable();
while let Some(stmt) = it.next() {
if_let_chain! {[
let Some(expr) = it.peek(),
let hir::StmtDecl(ref decl, _) = stmt.node,
let hir::DeclLocal(ref decl) = decl.node,
let hir::PatKind::Binding(mode, ref name, None) = decl.pat.node,
let Some(def) = cx.tcx.def_map.borrow().get(&decl.pat.id),
let hir::PatKind::Binding(mode, def_id, ref name, None) = decl.pat.node,
let hir::StmtExpr(ref if_, _) = expr.node,
let hir::ExprIf(ref cond, ref then, ref else_) = if_.node,
!used_in_expr(cx, def.full_def().def_id(), cond),
let Some(value) = check_assign(cx, def.full_def().def_id(), then),
!used_in_expr(cx, def.full_def().def_id(), value),
!used_in_expr(cx, def_id, cond),
let Some(value) = check_assign(cx, def_id, then),
!used_in_expr(cx, def_id, value),
], {
let span = codemap::mk_sp(stmt.span.lo, if_.span.hi);
let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
if let hir::ExprBlock(ref else_) = else_.node {
if let Some(default) = check_assign(cx, def.full_def().def_id(), else_) {
if let Some(default) = check_assign(cx, def_id, else_) {
(else_.stmts.len() > 1, default)
} else if let Some(ref default) = decl.init {
(true, &**default)
@ -134,29 +133,34 @@ struct UsedVisitor<'a, 'tcx: 'a> {
used: bool,
}
impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UsedVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'v hir::Expr) {
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if_let_chain! {[
let hir::ExprPath(None, _) = expr.node,
let Some(def) = self.cx.tcx.def_map.borrow().get(&expr.id),
self.id == def.full_def().def_id(),
let hir::ExprPath(ref qpath) = expr.node,
self.id == self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id(),
], {
self.used = true;
return;
}}
hir::intravisit::walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
hir::intravisit::NestedVisitorMap::All(&self.cx.tcx.map)
}
}
fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir::Block) -> Option<&'e hir::Expr> {
fn check_assign<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
decl: hir::def_id::DefId,
block: &'tcx hir::Block,
) -> Option<&'tcx hir::Expr> {
if_let_chain! {[
block.expr.is_none(),
let Some(expr) = block.stmts.iter().last(),
let hir::StmtSemi(ref expr, _) = expr.node,
let hir::ExprAssign(ref var, ref value) = expr.node,
let hir::ExprPath(None, _) = var.node,
let Some(def) = cx.tcx.def_map.borrow().get(&var.id),
decl == def.full_def().def_id(),
let hir::ExprPath(ref qpath) = var.node,
decl == cx.tcx.tables().qpath_def(qpath, var.id).def_id(),
], {
let mut v = UsedVisitor {
cx: cx,
@ -178,7 +182,11 @@ fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir::
None
}
fn used_in_expr(cx: &LateContext, id: hir::def_id::DefId, expr: &hir::Expr) -> bool {
fn used_in_expr<'a, 'tcx: 'a>(
cx: &LateContext<'a, 'tcx>,
id: hir::def_id::DefId,
expr: &'tcx hir::Expr,
) -> bool {
let mut v = UsedVisitor {
cx: cx,
id: id,

View File

@ -9,6 +9,7 @@
#![feature(repeat_str)]
#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)]
#![allow(needless_lifetimes)]
#[macro_use]
extern crate syntax;
@ -256,7 +257,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold));
reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents));
reg.register_late_lint_pass(box neg_multiply::NegMultiply);
reg.register_late_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval);
reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval);
reg.register_late_lint_pass(box mem_forget::MemForget);
reg.register_late_lint_pass(box arithmetic::Arithmetic::default());
reg.register_late_lint_pass(box assign_ops::AssignOps);

View File

@ -2,10 +2,10 @@ use reexport::*;
use rustc::lint::*;
use rustc::hir::def::Def;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics};
use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics, NestedVisitorMap};
use std::collections::{HashSet, HashMap};
use syntax::codemap::Span;
use utils::{in_external_macro, span_lint};
use utils::{in_external_macro, span_lint, last_path_segment};
/// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
@ -56,20 +56,20 @@ impl LintPass for LifetimePass {
}
}
impl LateLintPass for LifetimePass {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
check_fn_inner(cx, decl, generics, item.span);
}
}
fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
if let ImplItemKind::Method(ref sig, _) = item.node {
check_fn_inner(cx, &sig.decl, &sig.generics, item.span);
}
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
if let MethodTraitItem(ref sig, _) = item.node {
check_fn_inner(cx, &sig.decl, &sig.generics, item.span);
}
@ -98,7 +98,12 @@ fn bound_lifetimes(bound: &TyParamBound) -> HirVec<&Lifetime> {
}
}
fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &Generics, span: Span) {
fn check_fn_inner<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
decl: &'tcx FnDecl,
generics: &'tcx Generics,
span: Span,
) {
if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) {
return;
}
@ -116,9 +121,16 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &Generics, span: Sp
report_extra_lifetimes(cx, decl, generics);
}
fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl,
named_lts: &[LifetimeDef], bounds_lts: T)
-> bool {
fn could_use_elision<
'a,
'tcx: 'a,
T: Iterator<Item = &'tcx Lifetime>
>(
cx: &LateContext<'a, 'tcx>,
func: &'tcx FnDecl,
named_lts: &'tcx [LifetimeDef],
bounds_lts: T,
) -> bool {
// There are two scenarios where elision works:
// * no output references, all input references have different LT
// * output references, exactly one input reference with same LT
@ -210,8 +222,8 @@ fn unique_lifetimes(lts: &[RefLt]) -> usize {
}
/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>,
struct RefVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
lts: Vec<RefLt>,
}
@ -239,56 +251,57 @@ impl<'v, 't> RefVisitor<'v, 't> {
self.lts
}
fn collect_anonymous_lifetimes(&mut self, path: &Path, ty: &Ty) {
let last_path_segment = path.segments.last().map(|s| &s.parameters);
if let Some(&AngleBracketedParameters(ref params)) = last_path_segment {
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
let last_path_segment = &last_path_segment(qpath).parameters;
if let AngleBracketedParameters(ref params) = *last_path_segment {
if params.lifetimes.is_empty() {
if let Some(def) = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()) {
match def {
Def::TyAlias(def_id) |
Def::Struct(def_id) => {
let generics = self.cx.tcx.item_generics(def_id);
for _ in generics.regions.as_slice() {
self.record(&None);
}
match self.cx.tcx.tables().qpath_def(qpath, ty.id) {
Def::TyAlias(def_id) |
Def::Struct(def_id) => {
let generics = self.cx.tcx.item_generics(def_id);
for _ in generics.regions.as_slice() {
self.record(&None);
}
Def::Trait(def_id) => {
let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id];
for _ in &trait_def.generics.regions {
self.record(&None);
}
}
_ => (),
}
Def::Trait(def_id) => {
let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id];
for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions {
self.record(&None);
}
}
_ => (),
}
}
}
}
}
impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> {
impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
self.record(&Some(*lifetime));
}
fn visit_ty(&mut self, ty: &'v Ty) {
fn visit_ty(&mut self, ty: &'tcx Ty) {
match ty.node {
TyRptr(None, _) => {
self.record(&None);
}
TyPath(_, ref path) => {
TyPath(ref path) => {
self.collect_anonymous_lifetimes(path, ty);
}
_ => (),
}
walk_ty(self, ty);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
}
/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
/// reason about elision.
fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool {
fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool {
for predicate in &where_clause.predicates {
match *predicate {
WherePredicate::RegionPredicate(..) => return true,
@ -325,34 +338,39 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool {
false
}
struct LifetimeChecker(HashMap<Name, Span>);
struct LifetimeChecker {
map: HashMap<Name, Span>,
}
impl<'v> Visitor<'v> for LifetimeChecker {
impl<'tcx> Visitor<'tcx> for LifetimeChecker {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
self.0.remove(&lifetime.name);
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
self.map.remove(&lifetime.name);
}
fn visit_lifetime_def(&mut self, _: &'v LifetimeDef) {
fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) {
// don't actually visit `<'a>` or `<'a: 'b>`
// we've already visited the `'a` declarations and
// don't want to spuriously remove them
// `'b` in `'a: 'b` is useless unless used elsewhere in
// a non-lifetime bound
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
}
fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) {
fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
let hs = generics.lifetimes
.iter()
.map(|lt| (lt.lifetime.name, lt.lifetime.span))
.collect();
let mut checker = LifetimeChecker(hs);
let mut checker = LifetimeChecker { map: hs };
walk_generics(&mut checker, generics);
walk_fn_decl(&mut checker, func);
for &v in checker.0.values() {
for &v in checker.map.values() {
span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
}
}

View File

@ -2,7 +2,7 @@ use reexport::*;
use rustc::hir::*;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl};
use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl, NestedVisitorMap};
use rustc::hir::map::Node::NodeBlock;
use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
@ -16,7 +16,7 @@ use utils::sugg;
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg,
in_external_macro, is_refutable, span_help_and_lint, is_integer_literal,
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty};
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty, last_path_segment};
use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some
@ -307,8 +307,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let Some((pat, arg, body)) = higher::for_loop(expr) {
check_for_loop(cx, pat, arg, body, expr);
}
@ -366,33 +366,32 @@ impl LateLintPass for Pass {
}
if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node {
let pat = &arms[0].pats[0].node;
if let (&PatKind::TupleStruct(ref path, ref pat_args, _),
if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _),
&ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) {
let iter_expr = &method_args[0];
if let Some(lhs_constructor) = path.segments.last() {
if &*method_name.node.as_str() == "next" &&
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
&*lhs_constructor.name.as_str() == "Some" &&
!is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");
span_lint_and_then(cx,
WHILE_LET_ON_ITERATOR,
expr.span,
"this loop could be written as a `for` loop",
|db| {
db.span_suggestion(expr.span,
"try",
format!("for {} in {} {{ .. }}", loop_var, iterator));
});
}
let lhs_constructor = last_path_segment(qpath);
if &*method_name.node.as_str() == "next" &&
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
&*lhs_constructor.name.as_str() == "Some" &&
!is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");
span_lint_and_then(cx,
WHILE_LET_ON_ITERATOR,
expr.span,
"this loop could be written as a `for` loop",
|db| {
db.span_suggestion(expr.span,
"try",
format!("for {} in {} {{ .. }}", loop_var, iterator));
});
}
}
}
}
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
if let StmtSemi(ref expr, _) = stmt.node {
if let ExprMethodCall(ref method, _, ref args) = expr.node {
if args.len() == 1 && &*method.node.as_str() == "collect" &&
@ -408,7 +407,13 @@ impl LateLintPass for Pass {
}
}
fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
fn check_for_loop<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
check_for_loop_range(cx, pat, arg, body, expr);
check_for_loop_reverse_range(cx, arg, expr);
check_for_loop_arg(cx, pat, arg, expr);
@ -418,13 +423,19 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E
/// Check for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal.
fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
fn check_for_loop_range<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::range(arg) {
// the var must be a single name
if let PatKind::Binding(_, ref ident, _) = pat.node {
if let PatKind::Binding(_, def_id, ref ident, _) = pat.node {
let mut visitor = VarVisitor {
cx: cx,
var: cx.tcx.expect_def(pat.id).def_id(),
var: def_id,
indexed: HashMap::new(),
nonindex: false,
};
@ -510,7 +521,7 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {
let ExprMethodCall(method, _, ref len_args) = expr.node,
len_args.len() == 1,
&*method.node.as_str() == "len",
let ExprPath(_, ref path) = len_args[0].node,
let ExprPath(QPath::Resolved(_, ref path)) = len_args[0].node,
path.segments.len() == 1,
&path.segments[0].name == var
], {
@ -647,7 +658,12 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) {
}
}
fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) {
fn check_for_loop_explicit_counter<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
// Look for variables that are incremented once per loop iteration.
let mut visitor = IncrementVisitor {
cx: cx,
@ -692,14 +708,20 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex
}
/// Check for the `FOR_KV_MAP` lint.
fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
fn check_for_loop_over_map_kv<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
let pat_span = pat.span;
if let PatKind::Tuple(ref pat, _) = pat.node {
if pat.len() == 2 {
let (new_pat_span, kind) = match (&pat[0].node, &pat[1].node) {
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value"),
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key"),
(key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value"),
(_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key"),
_ => return,
};
@ -729,13 +751,18 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex
}
/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`.
fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool {
fn pat_is_wild<'a, 'tcx: 'a>(
cx: &LateContext<'a, 'tcx>,
pat: &'tcx PatKind,
body: &'tcx Expr,
) -> bool {
match *pat {
PatKind::Wild => true,
PatKind::Binding(_, ident, None) if ident.node.as_str().starts_with('_') => {
PatKind::Binding(_, _, ident, None) if ident.node.as_str().starts_with('_') => {
let mut visitor = UsedVisitor {
var: ident.node,
used: false,
cx: cx,
};
walk_expr(&mut visitor, body);
!visitor.used
@ -744,14 +771,15 @@ fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool {
}
}
struct UsedVisitor {
struct UsedVisitor<'a, 'tcx: 'a> {
var: ast::Name, // var to look for
used: bool, // has the var been used otherwise?
cx: &'a LateContext<'a, 'tcx>,
}
impl<'a> Visitor<'a> for UsedVisitor {
fn visit_expr(&mut self, expr: &Expr) {
if let ExprPath(None, ref path) = expr.node {
impl<'a, 'tcx: 'a> Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if let ExprPath(QPath::Resolved(None, ref path)) = expr.node {
if path.segments.len() == 1 && path.segments[0].name == self.var {
self.used = true;
return;
@ -760,31 +788,35 @@ impl<'a> Visitor<'a> for UsedVisitor {
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
struct VarVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>, // context reference
struct VarVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
var: DefId, // var name to look for as index
indexed: HashMap<Name, Option<CodeExtent>>, // indexed variables, the extent is None for global
nonindex: bool, // has the var been used otherwise?
}
impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
fn visit_expr(&mut self, expr: &'v Expr) {
if let ExprPath(None, ref path) = expr.node {
if path.segments.len() == 1 && self.cx.tcx.expect_def(expr.id).def_id() == self.var {
// we are referencing our variable! now check if it's as an index
if_let_chain! {[
let Some(parexpr) = get_parent_expr(self.cx, expr),
let ExprIndex(ref seqexpr, _) = parexpr.node,
let ExprPath(None, ref seqvar) = seqexpr.node,
seqvar.segments.len() == 1
], {
let def_map = self.cx.tcx.def_map.borrow();
if let Some(def) = def_map.get(&seqexpr.id) {
match def.base_def {
impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if let ExprPath(ref qpath) = expr.node {
if let QPath::Resolved(None, ref path) = *qpath {
if path.segments.len() == 1 && self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id() == self.var {
// we are referencing our variable! now check if it's as an index
if_let_chain! {[
let Some(parexpr) = get_parent_expr(self.cx, expr),
let ExprIndex(ref seqexpr, _) = parexpr.node,
let ExprPath(ref seqpath) = seqexpr.node,
let QPath::Resolved(None, ref seqvar) = *seqpath,
seqvar.segments.len() == 1
], {
let def = self.cx.tcx.tables().qpath_def(seqpath, seqexpr.id);
match def {
Def::Local(..) | Def::Upvar(..) => {
let def_id = def.base_def.def_id();
let def_id = def.def_id();
let node_id = self.cx.tcx.map.as_local_node_id(def_id).unwrap();
let extent = self.cx.tcx.region_maps.var_scope(node_id);
@ -797,18 +829,21 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
}
_ => (),
}
}
}}
// we are not indexing anything, record that
self.nonindex = true;
return;
}}
// we are not indexing anything, record that
self.nonindex = true;
return;
}
}
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool {
fn is_iterator_used_after_while_let<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, iter_expr: &'tcx Expr) -> bool {
let def_id = match var_def_id(cx, iter_expr) {
Some(id) => id,
None => return false,
@ -826,16 +861,16 @@ fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool
visitor.var_used_after_while_let
}
struct VarUsedAfterLoopVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>,
struct VarUsedAfterLoopVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
def_id: NodeId,
iter_expr_id: NodeId,
past_while_let: bool,
var_used_after_while_let: bool,
}
impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> {
fn visit_expr(&mut self, expr: &'v Expr) {
impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if self.past_while_let {
if Some(self.def_id) == var_def_id(self.cx, expr) {
self.var_used_after_while_let = true;
@ -845,6 +880,9 @@ impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> {
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
@ -935,15 +973,15 @@ enum VarState {
}
/// Scan a for loop for variables that are incremented exactly once.
struct IncrementVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>, // context reference
struct IncrementVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
states: HashMap<NodeId, VarState>, // incremented variables
depth: u32, // depth of conditional expressions
done: bool,
}
impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> {
fn visit_expr(&mut self, expr: &'v Expr) {
impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if self.done {
return;
}
@ -984,12 +1022,15 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> {
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
/// Check whether a variable is initialized to zero at the start of a loop.
struct InitializeVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>, // context reference
end_expr: &'v Expr, // the for loop. Stop scanning here.
struct InitializeVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
end_expr: &'tcx Expr, // the for loop. Stop scanning here.
var_id: NodeId,
state: VarState,
name: Option<Name>,
@ -997,12 +1038,12 @@ struct InitializeVisitor<'v, 't: 'v> {
past_loop: bool,
}
impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> {
fn visit_decl(&mut self, decl: &'v Decl) {
impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
fn visit_decl(&mut self, decl: &'tcx Decl) {
// Look for declarations of the variable
if let DeclLocal(ref local) = decl.node {
if local.pat.id == self.var_id {
if let PatKind::Binding(_, ref ident, _) = local.pat.node {
if let PatKind::Binding(_, _, ref ident, _) = local.pat.node {
self.name = Some(ident.node);
self.state = if let Some(ref init) = local.init {
@ -1020,7 +1061,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> {
walk_decl(self, decl);
}
fn visit_expr(&mut self, expr: &'v Expr) {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if self.state == VarState::DontWarn {
return;
}
@ -1068,11 +1109,15 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> {
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> {
if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) {
if let Def::Local(def_id) = path_res.base_def {
if let ExprPath(ref qpath) = expr.node {
let path_res = cx.tcx.tables().qpath_def(qpath, expr.id);
if let Def::Local(def_id) = path_res {
let node_id = cx.tcx.map.as_local_node_id(def_id).expect("That DefId should be valid");
return Some(node_id);
}

View File

@ -24,14 +24,14 @@ declare_lint! {
#[derive(Copy, Clone)]
pub struct Pass;
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// call to .map()
if let ExprMethodCall(name, _, ref args) = expr.node {
if &*name.node.as_str() == "map" && args.len() == 2 {
match args[1].node {
ExprClosure(_, ref decl, ref closure_expr, _) => {
let closure_expr = remove_blocks(closure_expr);
ExprClosure(_, ref decl, closure_eid, _) => {
let closure_expr = remove_blocks(cx.tcx.map.expr(closure_eid));
if_let_chain! {[
// nothing special in the argument, besides reference bindings
// (e.g. .map(|&x| x) )
@ -64,7 +64,7 @@ impl LateLintPass for Pass {
}
}}
}
ExprPath(_, ref path) => {
ExprPath(ref path) => {
if match_path(path, &paths::CLONE) {
let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");
span_help_and_lint(cx,
@ -85,7 +85,7 @@ impl LateLintPass for Pass {
fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool {
match expr.node {
ExprPath(None, ref path) => {
ExprPath(QPath::Resolved(None, ref path)) => {
let arg_segment = [PathSegment {
name: id,
parameters: PathParameters::none(),
@ -108,7 +108,7 @@ fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static s
fn get_arg_name(pat: &Pat) -> Option<ast::Name> {
match pat.node {
PatKind::Binding(_, name, None) => Some(name.node),
PatKind::Binding(_, _, name, None) => Some(name.node),
PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
_ => None,
}

View File

@ -129,8 +129,8 @@ impl LintPass for MatchPass {
}
}
impl LateLintPass for MatchPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if in_external_macro(cx, expr.span) {
return;
}
@ -210,8 +210,8 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr:
}
path.to_string()
}
PatKind::Binding(BindByValue(MutImmutable), ident, None) => ident.node.to_string(),
PatKind::Path(None, ref path) => path.to_string(),
PatKind::Binding(BindByValue(MutImmutable), _, ident, None) => ident.node.to_string(),
PatKind::Path(ref path) => path.to_string(),
_ => return,
};

View File

@ -27,11 +27,11 @@ impl LintPass for MemForget {
}
}
impl LateLintPass for MemForget {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprCall(ref path_expr, ref args) = e.node {
if let ExprPath(None, _) = path_expr.node {
let def_id = cx.tcx.expect_def(path_expr.id).def_id();
if let ExprPath(ref qpath) = path_expr.node {
let def_id = cx.tcx.tables().qpath_def(qpath, path_expr.id).def_id();
if match_def_path(cx, def_id, &paths::MEM_FORGET) {
let forgot_ty = cx.tcx.tables().expr_ty(&args[0]);

View File

@ -3,6 +3,7 @@ use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::middle::const_qualif::ConstQualif;
use rustc::ty;
use rustc::hir::def::Def;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::eval_const_expr_partial;
use std::borrow::Cow;
@ -10,7 +11,8 @@ use std::fmt;
use syntax::codemap::Span;
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path,
match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet,
span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth,
last_path_segment, single_segment_path, match_def_path};
use utils::paths;
use utils::sugg;
@ -547,11 +549,11 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
#[allow(unused_attributes)]
// ^ required because `cyclomatic_complexity` attribute shows up as unused
#[cyclomatic_complexity = "30"]
fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
if in_macro(cx, expr.span) {
return;
}
@ -627,7 +629,7 @@ impl LateLintPass for Pass {
}
}
fn check_impl_item(&mut self, cx: &LateContext, implitem: &hir::ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, implitem: &'tcx hir::ImplItem) {
if in_external_macro(cx, implitem.span) {
return;
}
@ -701,12 +703,8 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
}
if name == "unwrap_or" {
if let hir::ExprPath(_, ref path) = fun.node {
let path: &str = &path.segments
.last()
.expect("A path must have at least one segment")
.name
.as_str();
if let hir::ExprPath(ref qpath) = fun.node {
let path: &str = &*last_path_segment(qpath).name.as_str();
if ["default", "new"].contains(&path) {
let arg_ty = cx.tcx.tables().expr_ty(arg);
@ -877,8 +875,9 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
if_let_chain!{[
let hir::ExprCall(ref fun, ref args) = new.node,
args.len() == 1,
let hir::ExprPath(None, ref path) = fun.node,
match_path(path, &paths::CSTRING_NEW),
let hir::ExprPath(ref path) = fun.node,
let Def::Method(did) = cx.tcx.tables().qpath_def(path, fun.id),
match_def_path(cx, did, &paths::CSTRING_NEW)
], {
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
"you are getting the inner pointer of a temporary `CString`",
@ -1188,8 +1187,9 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other:
let Some(args) = method_chain_args(chain, &["chars", "next"]),
let hir::ExprCall(ref fun, ref arg_char) = other.node,
arg_char.len() == 1,
let hir::ExprPath(None, ref path) = fun.node,
path.segments.len() == 1 && &*path.segments[0].name.as_str() == "Some"
let hir::ExprPath(ref qpath) = fun.node,
let Some(segment) = single_segment_path(qpath),
&*segment.name.as_str() == "Some"
], {
let self_ty = walk_ptrs_ty(cx.tcx.tables().expr_ty_adjusted(&args[0][0]));
@ -1408,7 +1408,7 @@ impl OutType {
}
fn is_bool(ty: &hir::Ty) -> bool {
if let hir::TyPath(None, ref p) = ty.node {
if let hir::TyPath(ref p) = ty.node {
match_path(p, &["bool"])
} else {
false

View File

@ -33,8 +33,8 @@ impl LintPass for MinMaxPass {
}
}
impl LateLintPass for MinMaxPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
if let Some((inner_max, inner_c, _)) = min_max(cx, oe) {
if outer_max == inner_max {
@ -61,8 +61,8 @@ enum MinMax {
fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &'a Expr)> {
if let ExprCall(ref path, ref args) = expr.node {
if let ExprPath(None, _) = path.node {
let def_id = cx.tcx.expect_def(path.id).def_id();
if let ExprPath(ref qpath) = path.node {
let def_id = cx.tcx.tables().qpath_def(qpath, path.id).def_id();
if match_def_path(cx, def_id, &paths::CMP_MIN) {
fetch_const(args, MinMax::Min)

View File

@ -10,7 +10,7 @@ use rustc_const_math::ConstFloat;
use syntax::codemap::{Span, Spanned, ExpnFormat};
use utils::{
get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path,
snippet, span_lint, span_lint_and_then, walk_ptrs_ty
snippet, span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment
};
use utils::sugg::Sugg;
@ -166,14 +166,14 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Expr, _: Span, _: NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, k: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span, _: NodeId) {
if let FnKind::Closure(_) = k {
// Does not apply to closures
return;
}
for arg in &decl.inputs {
if let PatKind::Binding(BindByRef(_), _, _) = arg.pat.node {
if let PatKind::Binding(BindByRef(_), _, _, _) = arg.pat.node {
span_lint(cx,
TOPLEVEL_REF_ARG,
arg.pat.span,
@ -182,11 +182,11 @@ impl LateLintPass for Pass {
}
}
fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) {
if_let_chain! {[
let StmtDecl(ref d, _) = s.node,
let DeclLocal(ref l) = d.node,
let PatKind::Binding(BindByRef(mt), i, None) = l.pat.node,
let PatKind::Binding(BindByRef(mt), _, i, None) = l.pat.node,
let Some(ref init) = l.init
], {
let init = Sugg::hir(cx, init, "..");
@ -216,14 +216,14 @@ impl LateLintPass for Pass {
}}
}
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
let op = cmp.node;
if op.is_comparison() {
if let ExprPath(_, ref path) = left.node {
if let ExprPath(QPath::Resolved(_, ref path)) = left.node {
check_nan(cx, path, expr.span);
}
if let ExprPath(_, ref path) = right.node {
if let ExprPath(QPath::Resolved(_, ref path)) = right.node {
check_nan(cx, path, expr.span);
}
check_to_owned(cx, left, right, true, cmp.span);
@ -262,18 +262,14 @@ impl LateLintPass for Pass {
return;
}
let binding = match expr.node {
ExprPath(_, ref path) => {
let binding = path.segments
.last()
.expect("path should always have at least one segment")
.name
.as_str();
ExprPath(ref qpath) => {
let binding = last_path_segment(qpath).name.as_str();
if binding.starts_with('_') &&
!binding.starts_with("__") &&
&*binding != "_result" && // FIXME: #944
is_used(cx, expr) &&
// don't lint if the declaration is in a macro
non_macro_local(cx, &cx.tcx.expect_def(expr.id)) {
non_macro_local(cx, &cx.tcx.tables().qpath_def(qpath, expr.id)) {
Some(binding)
} else {
None
@ -298,8 +294,8 @@ impl LateLintPass for Pass {
}
}
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
if let PatKind::Binding(_, ref ident, Some(ref right)) = pat.node {
fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
if let PatKind::Binding(_, _, ref ident, Some(ref right)) = pat.node {
if right.node == PatKind::Wild {
span_lint(cx,
REDUNDANT_PATTERN,
@ -366,7 +362,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S
}
}
ExprCall(ref path, ref v) if v.len() == 1 => {
if let ExprPath(None, ref path) = path.node {
if let ExprPath(ref path) = path.node {
if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) {
(cx.tcx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
} else {
@ -444,9 +440,7 @@ fn in_attributes_expansion(cx: &LateContext, expr: &Expr) -> bool {
fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
match *def {
def::Def::Local(id) | def::Def::Upvar(id, _, _) => {
let id = cx.tcx.map.as_local_node_id(id).expect("That DefId should be valid");
if let Some(span) = cx.tcx.map.opt_span(id) {
if let Some(span) = cx.tcx.map.span_if_local(id) {
!in_macro(cx, span)
} else {
true

View File

@ -94,8 +94,8 @@ impl LintPass for MissingDoc {
}
}
impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
None => false,
@ -105,15 +105,15 @@ impl LateLintPass for MissingDoc {
self.doc_hidden_stack.push(doc_hidden);
}
fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) {
fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) {
self.check_missing_docs_attrs(cx, &krate.attrs, krate.span, "crate");
}
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
let desc = match it.node {
hir::ItemConst(..) => "a constant",
hir::ItemEnum(..) => "an enum",
@ -134,7 +134,7 @@ impl LateLintPass for MissingDoc {
self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc);
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir::TraitItem) {
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
hir::MethodTraitItem(..) => "a trait method",
@ -144,7 +144,7 @@ impl LateLintPass for MissingDoc {
self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, desc);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
// If the method is an impl for a trait, don't doc.
let def_id = cx.tcx.map.local_def_id(impl_item.id);
match cx.tcx.associated_item(def_id).container {
@ -164,13 +164,13 @@ impl LateLintPass for MissingDoc {
self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc);
}
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, sf: &'tcx hir::StructField) {
if !sf.is_positional() {
self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a struct field");
}
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, v: &'tcx hir::Variant, _: &hir::Generics) {
self.check_missing_docs_attrs(cx, &v.node.attrs, v.span, "a variant");
}
}

View File

@ -31,12 +31,12 @@ impl LintPass for MutMut {
}
}
impl LateLintPass for MutMut {
fn check_block(&mut self, cx: &LateContext, block: &hir::Block) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut {
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
intravisit::walk_block(&mut MutVisitor { cx: cx }, block);
}
fn check_ty(&mut self, cx: &LateContext, ty: &hir::Ty) {
fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &'tcx hir::Ty) {
use rustc::hir::intravisit::Visitor;
MutVisitor { cx: cx }.visit_ty(ty);
@ -47,8 +47,8 @@ pub struct MutVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'v hir::Expr) {
impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if in_external_macro(self.cx, expr.span) {
return;
}
@ -74,7 +74,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> {
}
}
fn visit_ty(&mut self, ty: &hir::Ty) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyRptr(_, hir::MutTy { ty: ref pty, mutbl: hir::MutMutable }) = ty.node {
if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node {
span_lint(self.cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible");
@ -84,4 +84,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> {
intravisit::walk_ty(self, ty);
}
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
intravisit::NestedVisitorMap::All(&self.cx.tcx.map)
}
}

View File

@ -32,8 +32,8 @@ impl LintPass for UnnecessaryMutPassed {
}
}
impl LateLintPass for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
let borrowed_table = cx.tcx.tables.borrow();
match e.node {
ExprCall(ref fn_expr, ref arguments) => {
@ -42,7 +42,7 @@ impl LateLintPass for UnnecessaryMutPassed {
.expect("A function with an unknown type is called. \
If this happened, the compiler would have \
aborted the compilation long ago");
if let ExprPath(_, ref path) = fn_expr.node {
if let ExprPath(ref path) = fn_expr.node {
check_arguments(cx, arguments, function_type, &path.to_string());
}
}
@ -60,7 +60,7 @@ fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS,
match type_definition.sty {
TypeVariants::TyFnDef(_, _, fn_type) |
TypeVariants::TyFnPtr(fn_type) => {
let parameters = &fn_type.sig.skip_binder().inputs;
let parameters = fn_type.sig.skip_binder().inputs();
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty {
TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) |

View File

@ -54,8 +54,8 @@ impl LintPass for MutexAtomic {
pub struct MutexAtomic;
impl LateLintPass for MutexAtomic {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
let ty = cx.tcx.tables().expr_ty(expr);
if let ty::TyAdt(_, subst) = ty.sty {
if match_type(cx, ty, &paths::MUTEX) {

View File

@ -56,8 +56,8 @@ impl LintPass for NeedlessBool {
}
}
impl LateLintPass for NeedlessBool {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
use self::Expression::*;
if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node {
let reduce = |ret, not| {
@ -116,8 +116,8 @@ impl LintPass for BoolComparison {
}
}
impl LateLintPass for BoolComparison {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
use self::Expression::*;
if let ExprBinary(Spanned { node: BiEq, .. }, ref left_side, ref right_side) = e.node {
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {

View File

@ -34,8 +34,8 @@ impl LintPass for NeedlessBorrow {
}
}
impl LateLintPass for NeedlessBorrow {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if in_macro(cx, e.span) {
return;
}
@ -53,11 +53,11 @@ impl LateLintPass for NeedlessBorrow {
}
}
}
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
if in_macro(cx, pat.span) {
return;
}
if let PatKind::Binding(BindingMode::BindByRef(MutImmutable), _, _) = pat.node {
if let PatKind::Binding(BindingMode::BindByRef(MutImmutable), _, _, _) = pat.node {
if let ty::TyRef(_, ref tam) = cx.tcx.tables().pat_ty(pat).sty {
if tam.mutbl == MutImmutable {
if let ty::TyRef(..) = tam.ty.sty {

View File

@ -30,8 +30,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprStruct(_, ref fields, Some(ref base)) = expr.node {
let ty = cx.tcx.tables().expr_ty(expr);
if let TyAdt(def, _) = ty.sty {

View File

@ -31,8 +31,8 @@ impl LintPass for NegMultiply {
}
#[allow(match_same_arms)]
impl LateLintPass for NegMultiply {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprBinary(Spanned { node: BiMul, .. }, ref l, ref r) = e.node {
match (&l.node, &r.node) {
(&ExprUnary(..), &ExprUnary(..)) => (),

View File

@ -89,8 +89,16 @@ impl LintPass for NewWithoutDefault {
}
}
impl LateLintPass for NewWithoutDefault {
fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Expr, span: Span, id: ast::NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
_: &'tcx hir::Expr,
span: Span,
id: ast::NodeId,
) {
if in_external_macro(cx, span) {
return;
}

View File

@ -1,5 +1,5 @@
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::hir::def::{Def, PathResolution};
use rustc::hir::def::Def;
use rustc::hir::{Expr, Expr_, Stmt, StmtSemi, BlockCheckMode, UnsafeSource};
use utils::{in_macro, span_lint, snippet_opt, span_lint_and_then};
use std::ops::Deref;
@ -68,13 +68,17 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
}
}
Expr_::ExprCall(ref callee, ref args) => {
let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
match def {
Some(Def::Struct(..)) |
Some(Def::Variant(..)) |
Some(Def::StructCtor(..)) |
Some(Def::VariantCtor(..)) => args.iter().all(|arg| has_no_effect(cx, arg)),
_ => false,
if let Expr_::ExprPath(ref qpath) = callee.node {
let def = cx.tcx.tables().qpath_def(qpath, callee.id);
match def {
Def::Struct(..) |
Def::Variant(..) |
Def::StructCtor(..) |
Def::VariantCtor(..) => args.iter().all(|arg| has_no_effect(cx, arg)),
_ => false,
}
} else {
false
}
}
Expr_::ExprBlock(ref block) => {
@ -98,8 +102,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
if let StmtSemi(ref expr, _) = stmt.node {
if has_no_effect(cx, expr) {
span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
@ -146,12 +150,17 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
}
Expr_::ExprCall(ref callee, ref args) => {
match cx.tcx.def_map.borrow().get(&callee.id).map(PathResolution::full_def) {
Some(Def::Struct(..)) |
Some(Def::Variant(..)) |
Some(Def::StructCtor(..)) |
Some(Def::VariantCtor(..)) => Some(args.iter().collect()),
_ => None,
if let Expr_::ExprPath(ref qpath) = callee.node {
let def = cx.tcx.tables().qpath_def(qpath, callee.id);
match def {
Def::Struct(..) |
Def::Variant(..) |
Def::StructCtor(..) |
Def::VariantCtor(..) => Some(args.iter().collect()),
_ => None,
}
} else {
None
}
}
Expr_::ExprBlock(ref block) => {

View File

@ -59,9 +59,9 @@ struct ExistingName {
whitelist: &'static [&'static str],
}
struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
struct SimilarNamesLocalVisitor<'a, 'tcx: 'a> {
names: Vec<ExistingName>,
cx: &'a EarlyContext<'b>,
cx: &'a EarlyContext<'tcx>,
lint: &'a NonExpressiveNames,
single_char_names: Vec<char>,
}
@ -76,10 +76,10 @@ const WHITELIST: &'static [&'static [&'static str]] = &[
&["set", "get"],
];
struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>);
struct SimilarNamesNameVisitor<'a: 'b, 'tcx: 'a, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> {
fn visit_pat(&mut self, pat: &Pat) {
impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
fn visit_pat(&mut self, pat: &'tcx Pat) {
match pat.node {
PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name),
PatKind::Struct(_, ref fields, _) => {
@ -120,7 +120,7 @@ fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
false
}
impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
fn check_short_name(&mut self, c: char, span: Span) {
// make sure we ignore shadowing
if self.0.single_char_names.contains(&c) {
@ -236,18 +236,18 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
}
}
impl<'a, 'b> Visitor for SimilarNamesLocalVisitor<'a, 'b> {
fn visit_local(&mut self, local: &Local) {
impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
fn visit_local(&mut self, local: &'tcx Local) {
if let Some(ref init) = local.init {
self.apply(|this| walk_expr(this, &**init));
}
// add the pattern after the expression because the bindings aren't available yet in the init expression
SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
}
fn visit_block(&mut self, blk: &Block) {
fn visit_block(&mut self, blk: &'tcx Block) {
self.apply(|this| walk_block(this, blk));
}
fn visit_arm(&mut self, arm: &Arm) {
fn visit_arm(&mut self, arm: &'tcx Arm) {
self.apply(|this| {
// just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier
SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);

View File

@ -40,13 +40,13 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[ //begin checking variables
let ExprMatch(ref op, ref body, ref source) = expr.node, //test if expr is a match
let MatchSource::IfLetDesugar { .. } = *source, //test if it is an If Let
let ExprMethodCall(_, _, ref result_types) = op.node, //check is expr.ok() has type Result<T,E>.ok()
let PatKind::TupleStruct(ref x, ref y, _) = body[0].pats[0].node, //get operation
let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node, //get operation
method_chain_args(op, &["ok"]).is_some() //test to see if using ok() methoduse std::marker::Sized;
], {

View File

@ -32,8 +32,8 @@ impl LintPass for NonSensical {
}
}
impl LateLintPass for NonSensical {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSensical {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprMethodCall(ref name, _, ref arguments) = e.node {
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.tables().expr_ty(&arguments[0]));
if &*name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {

View File

@ -29,15 +29,15 @@ impl LintPass for OverflowCheckConditional {
}
}
impl LateLintPass for OverflowCheckConditional {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional {
// a + b < a, a > a + b, a < a - b, a - b > a
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node,
let Expr_::ExprPath(_,ref path1) = ident1.node,
let Expr_::ExprPath(_, ref path2) = ident2.node,
let Expr_::ExprPath(_, ref path3) = second.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = second.node,
&path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
cx.tcx.tables().expr_ty(ident1).is_integral(),
cx.tcx.tables().expr_ty(ident2).is_integral()
@ -57,9 +57,9 @@ impl LateLintPass for OverflowCheckConditional {
if_let_chain! {[
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node,
let Expr_::ExprPath(_,ref path1) = ident1.node,
let Expr_::ExprPath(_, ref path2) = ident2.node,
let Expr_::ExprPath(_, ref path3) = first.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = first.node,
&path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
cx.tcx.tables().expr_ty(ident1).is_integral(),
cx.tcx.tables().expr_ty(ident2).is_integral()

View File

@ -32,16 +32,15 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let ExprBlock(ref block) = expr.node,
let Some(ref ex) = block.expr,
let ExprCall(ref fun, ref params) = ex.node,
params.len() == 2,
let ExprPath(None, _) = fun.node,
let Some(fun) = resolve_node(cx, fun.id),
match_def_path(cx, fun.def_id(), &paths::BEGIN_PANIC),
let ExprPath(ref qpath) = fun.node,
match_def_path(cx, resolve_node(cx, qpath, fun.id).def_id(), &paths::BEGIN_PANIC),
let ExprLit(ref lit) = params[0].node,
is_direct_expn_of(cx, params[0].span, "panic").is_some(),
let LitKind::Str(ref string, _) = lit.node,

View File

@ -35,12 +35,12 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if_let_chain! {[
let ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) = item.node,
!is_automatically_derived(&*item.attrs),
cx.tcx.expect_def(trait_ref.ref_id).def_id() == cx.tcx.lang_items.eq_trait().unwrap(),
trait_ref.path.def.def_id() == cx.tcx.lang_items.eq_trait().unwrap(),
], {
for impl_item in impl_items {
if &*impl_item.name.as_str() == "ne" {

View File

@ -2,7 +2,7 @@ use rustc::hir::*;
use rustc::hir::map::Node::{NodeItem, NodeImplItem};
use rustc::lint::*;
use utils::paths;
use utils::{is_expn_of, match_path, match_def_path, resolve_node, span_lint};
use utils::{is_expn_of, match_def_path, resolve_node, span_lint, match_path_old};
use format::get_argument_fmtstr_parts;
/// **What it does:** This lint warns when you using `print!()` with a format string that
@ -65,13 +65,13 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let ExprCall(ref fun, ref args) = expr.node,
let ExprPath(..) = fun.node,
let Some(fun) = resolve_node(cx, fun.id),
let ExprPath(ref qpath) = fun.node,
], {
let fun = resolve_node(cx, qpath, fun.id);
let fun_id = fun.def_id();
// Search for `std::io::_print(..)` which is unique in a
@ -93,9 +93,8 @@ impl LateLintPass for Pass {
// ensure we're calling Arguments::new_v1
args.len() == 1,
let ExprCall(ref args_fun, ref args_args) = args[0].node,
let ExprPath(..) = args_fun.node,
let Some(def) = resolve_node(cx, args_fun.id),
match_def_path(cx, def.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
let ExprPath(ref qpath) = args_fun.node,
match_def_path(cx, resolve_node(cx, qpath, args_fun.id).def_id(), &paths::FMT_ARGUMENTS_NEWV1),
args_args.len() == 2,
let ExprAddrOf(_, ref match_expr) = args_args[1].node,
let ExprMatch(ref args, _, _) = match_expr.node,
@ -121,8 +120,8 @@ impl LateLintPass for Pass {
// Search for something like
// `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
else if args.len() == 2 && match_def_path(cx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
if let ExprPath(None, _) = args[1].node {
let def_id = resolve_node(cx, args[1].id).unwrap().def_id();
if let ExprPath(ref qpath) = args[1].node {
let def_id = cx.tcx.tables().qpath_def(qpath, args[1].id).def_id();
if match_def_path(cx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) &&
is_expn_of(cx, expr.span, "panic").is_none() {
span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
@ -141,7 +140,7 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
// `Debug` impl
if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
return match_path(&tr.path, &["Debug"]);
return match_path_old(&tr.path, &["Debug"]);
}
}
}

View File

@ -54,14 +54,14 @@ impl LintPass for PointerPass {
}
}
impl LateLintPass for PointerPass {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemFn(ref decl, _, _, _, _, _) = item.node {
check_fn(cx, decl, item.id);
}
}
fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
if let ImplItemKind::Method(ref sig, _) = item.node {
if let Some(NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) {
if let ItemImpl(_, _, _, Some(_), _, _) = it.node {
@ -72,13 +72,13 @@ impl LateLintPass for PointerPass {
}
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
if let MethodTraitItem(ref sig, _) = item.node {
check_fn(cx, &sig.decl, item.id);
}
}
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprBinary(ref op, ref l, ref r) = expr.node {
if (op.node == BiEq || op.node == BiNe) && (is_null_path(l) || is_null_path(r)) {
span_lint(cx,
@ -94,7 +94,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
let fn_def_id = cx.tcx.map.local_def_id(fn_id);
let fn_ty = cx.tcx.item_type(fn_def_id).fn_sig().skip_binder();
for (arg, ty) in decl.inputs.iter().zip(&fn_ty.inputs) {
for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) {
if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty {
if match_type(cx, ty, &paths::VEC) {
span_lint(cx,
@ -116,7 +116,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
fn is_null_path(expr: &Expr) -> bool {
if let ExprCall(ref pathexp, ref args) = expr.node {
if args.is_empty() {
if let ExprPath(_, ref path) = pathexp.node {
if let ExprPath(ref path) = pathexp.node {
return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT)
}
}

View File

@ -46,8 +46,8 @@ impl LintPass for StepByZero {
}
}
impl LateLintPass for StepByZero {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node {
let name = &*name.as_str();
@ -73,15 +73,15 @@ impl LateLintPass for StepByZero {
let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = end.node,
&*len_name.as_str() == "len" && len_args.len() == 1,
// .iter() and .len() called on same Path
let ExprPath(_, Path { segments: ref iter_path, .. }) = iter_args[0].node,
let ExprPath(_, Path { segments: ref len_path, .. }) = len_args[0].node,
iter_path == len_path
let ExprPath(QPath::Resolved(_, ref iter_path)) = iter_args[0].node,
let ExprPath(QPath::Resolved(_, ref len_path)) = len_args[0].node,
iter_path.segments == len_path.segments
], {
span_lint(cx,
RANGE_ZIP_WITH_LEN,
expr.span,
&format!("It is more idiomatic to use {}.iter().enumerate()",
snippet(cx, iter_args[0].span, "_")));
span_lint(cx,
RANGE_ZIP_WITH_LEN,
expr.span,
&format!("It is more idiomatic to use {}.iter().enumerate()",
snippet(cx, iter_args[0].span, "_")));
}}
}
}

View File

@ -82,12 +82,12 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_crate(&mut self, _: &LateContext, _: &Crate) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx Crate) {
self.spans.clear();
}
fn check_block(&mut self, cx: &LateContext, block: &Block) {
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
if_let_chain!{[
self.last.is_none(),
let Some(ref expr) = block.expr,
@ -106,19 +106,19 @@ impl LateLintPass for Pass {
}}
}
fn check_block_post(&mut self, _: &LateContext, block: &Block) {
fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, block: &'tcx Block) {
if self.last.map_or(false, |id| block.id == id) {
self.last = None;
}
}
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref fun, ref args) = expr.node,
let ExprPath(ref qpath) = fun.node,
args.len() == 1,
let Some(def) = cx.tcx.def_map.borrow().get(&fun.id),
], {
let def_id = def.full_def().def_id();
let def_id = cx.tcx.tables().qpath_def(qpath, fun.id).def_id();
if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
check_regex(cx, &args[0], true);

View File

@ -26,10 +26,10 @@ impl LintPass for Serde {
}
}
impl LateLintPass for Serde {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemImpl(_, _, _, Some(ref trait_ref), _, ref items) = item.node {
let did = cx.tcx.expect_def(trait_ref.ref_id).def_id();
let did = trait_ref.path.def.def_id();
if let Some(visit_did) = get_trait_def_id(cx, &paths::SERDE_DE_VISITOR) {
if did == visit_did {
let mut seen_str = None;

View File

@ -1,9 +1,8 @@
use reexport::*;
use rustc::lint::*;
use rustc::hir::def::Def;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, FnKind};
use std::ops::Deref;
use rustc::hir::intravisit::{Visitor, FnKind, NestedVisitorMap};
use rustc::ty;
use syntax::codemap::Span;
use utils::{higher, in_external_macro, snippet, span_lint_and_then};
@ -80,8 +79,16 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, expr: &Expr, _: Span, _: NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
decl: &'tcx FnDecl,
expr: &'tcx Expr,
_: Span,
_: NodeId,
) {
if in_external_macro(cx, expr.span) {
return;
}
@ -89,17 +96,17 @@ impl LateLintPass for Pass {
}
}
fn check_fn(cx: &LateContext, decl: &FnDecl, expr: &Expr) {
fn check_fn<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, expr: &'tcx Expr) {
let mut bindings = Vec::new();
for arg in &decl.inputs {
if let PatKind::Binding(_, ident, _) = arg.pat.node {
if let PatKind::Binding(_, _, ident, _) = arg.pat.node {
bindings.push((ident.node, ident.span))
}
}
check_expr(cx, expr, &mut bindings);
}
fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>) {
fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, bindings: &mut Vec<(Name, Span)>) {
let len = bindings.len();
for stmt in &block.stmts {
match stmt.node {
@ -114,7 +121,7 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>
bindings.truncate(len);
}
fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) {
fn check_decl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl, bindings: &mut Vec<(Name, Span)>) {
if in_external_macro(cx, decl.span) {
return;
}
@ -128,27 +135,33 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) {
}
if let Some(ref o) = *init {
check_expr(cx, o, bindings);
check_pat(cx, pat, &Some(o), span, bindings);
check_pat(cx, pat, Some(o), span, bindings);
} else {
check_pat(cx, pat, &None, span, bindings);
check_pat(cx, pat, None, span, bindings);
}
}
}
fn is_binding(cx: &LateContext, pat: &Pat) -> bool {
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
Some(Def::Variant(..)) |
Some(Def::Struct(..)) => false,
fn is_binding(cx: &LateContext, pat_id: NodeId) -> bool {
let var_ty = cx.tcx.tables().node_id_to_type(pat_id);
match var_ty.sty {
ty::TyAdt(..) => false,
_ => true,
}
}
fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) {
fn check_pat<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &'tcx Pat,
init: Option<&'tcx Expr>,
span: Span,
bindings: &mut Vec<(Name, Span)>,
) {
// TODO: match more stuff / destructuring
match pat.node {
PatKind::Binding(_, ref ident, ref inner) => {
PatKind::Binding(_, _, ref ident, ref inner) => {
let name = ident.node;
if is_binding(cx, pat) {
if is_binding(cx, pat.id) {
let mut new_binding = true;
for tup in bindings.iter_mut() {
if tup.0 == name {
@ -167,14 +180,14 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind
}
}
PatKind::Struct(_, ref pfields, _) => {
if let Some(init_struct) = *init {
if let Some(init_struct) = init {
if let ExprStruct(_, ref efields, _) = init_struct.node {
for field in pfields {
let name = field.node.name;
let efield = efields.iter()
.find(|f| f.name.node == name)
.map(|f| &*f.expr);
check_pat(cx, &field.node.pat, &efield, span, bindings);
check_pat(cx, &field.node.pat, efield, span, bindings);
}
} else {
for field in pfields {
@ -183,15 +196,15 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind
}
} else {
for field in pfields {
check_pat(cx, &field.node.pat, &None, span, bindings);
check_pat(cx, &field.node.pat, None, span, bindings);
}
}
}
PatKind::Tuple(ref inner, _) => {
if let Some(init_tup) = *init {
if let Some(init_tup) = init {
if let ExprTup(ref tup) = init_tup.node {
for (i, p) in inner.iter().enumerate() {
check_pat(cx, p, &Some(&tup[i]), p.span, bindings);
check_pat(cx, p, Some(&tup[i]), p.span, bindings);
}
} else {
for p in inner {
@ -200,14 +213,14 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind
}
} else {
for p in inner {
check_pat(cx, p, &None, span, bindings);
check_pat(cx, p, None, span, bindings);
}
}
}
PatKind::Box(ref inner) => {
if let Some(initp) = *init {
if let Some(initp) = init {
if let ExprBox(ref inner_init) = initp.node {
check_pat(cx, inner, &Some(&**inner_init), span, bindings);
check_pat(cx, inner, Some(&**inner_init), span, bindings);
} else {
check_pat(cx, inner, init, span, bindings);
}
@ -221,10 +234,15 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind
}
}
fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, init: &Option<T>, prev_span: Span)
where T: Deref<Target = Expr>
{
if let Some(ref expr) = *init {
fn lint_shadow<'a, 'tcx: 'a>(
cx: &LateContext<'a, 'tcx>,
name: Name,
span: Span,
pattern_span: Span,
init: Option<&'tcx Expr>,
prev_span: Span,
) {
if let Some(expr) = init {
if is_self_shadow(name, expr) {
span_lint_and_then(cx,
SHADOW_SAME,
@ -234,7 +252,7 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span,
snippet(cx, expr.span, "..")),
|db| { db.span_note(prev_span, "previous binding is here"); },
);
} else if contains_self(name, expr) {
} else if contains_self(cx, name, expr) {
span_lint_and_then(cx,
SHADOW_REUSE,
pattern_span,
@ -267,7 +285,7 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span,
}
}
fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings: &mut Vec<(Name, Span)>) {
if in_external_macro(cx, expr.span) {
return;
}
@ -302,7 +320,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
let len = bindings.len();
for arm in arms {
for pat in &arm.pats {
check_pat(cx, pat, &Some(&**init), pat.span, bindings);
check_pat(cx, pat, Some(&**init), pat.span, bindings);
// This is ugly, but needed to get the right type
if let Some(ref guard) = arm.guard {
check_expr(cx, guard, bindings);
@ -316,7 +334,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
}
}
fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) {
fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut Vec<(Name, Span)>) {
match ty.node {
TyObjectSum(ref sty, _) |
TySlice(ref sty) => check_ty(cx, sty, bindings),
@ -344,7 +362,7 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool {
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e))
}
ExprUnary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner),
ExprPath(_, ref path) => path_eq_name(name, path),
ExprPath(QPath::Resolved(_, ref path)) => path_eq_name(name, path),
_ => false,
}
}
@ -353,23 +371,28 @@ fn path_eq_name(name: Name, path: &Path) -> bool {
!path.global && path.segments.len() == 1 && path.segments[0].name.as_str() == name.as_str()
}
struct ContainsSelf {
struct ContainsSelf<'a, 'tcx: 'a> {
name: Name,
result: bool,
cx: &'a LateContext<'a, 'tcx>,
}
impl<'v> Visitor<'v> for ContainsSelf {
impl<'a, 'tcx: 'a> Visitor<'tcx> for ContainsSelf<'a, 'tcx> {
fn visit_name(&mut self, _: Span, name: Name) {
if self.name == name {
self.result = true;
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
fn contains_self(name: Name, expr: &Expr) -> bool {
fn contains_self<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, expr: &'tcx Expr) -> bool {
let mut cs = ContainsSelf {
name: name,
result: false,
cx: cx,
};
cs.visit_expr(expr);
cs.result

View File

@ -79,8 +79,8 @@ impl LintPass for StringAdd {
}
}
impl LateLintPass for StringAdd {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) = e.node {
if is_string(cx, left) {
if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
@ -136,8 +136,8 @@ impl LintPass for StringLitAsBytes {
}
}
impl LateLintPass for StringLitAsBytes {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
use std::ascii::AsciiExt;
use syntax::ast::LitKind;
use utils::{snippet, in_macro};

View File

@ -50,8 +50,8 @@ impl LintPass for Swap {
}
}
impl LateLintPass for Swap {
fn check_block(&mut self, cx: &LateContext, block: &Block) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
check_manual_swap(cx, block);
check_suspicious_swap(cx, block);
}
@ -65,7 +65,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
let StmtDecl(ref tmp, _) = w[0].node,
let DeclLocal(ref tmp) = tmp.node,
let Some(ref tmp_init) = tmp.init,
let PatKind::Binding(_, ref tmp_name, None) = tmp.pat.node,
let PatKind::Binding(_, _, ref tmp_name, None) = tmp.pat.node,
// foo() = bar();
let StmtSemi(ref first, _) = w[1].node,
@ -74,7 +74,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
// bar() = t;
let StmtSemi(ref second, _) = w[2].node,
let ExprAssign(ref lhs2, ref rhs2) = second.node,
let ExprPath(None, ref rhs2) = rhs2.node,
let ExprPath(QPath::Resolved(None, ref rhs2)) = rhs2.node,
rhs2.segments.len() == 1,
tmp_name.node.as_str() == rhs2.segments[0].name.as_str(),

View File

@ -37,8 +37,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprAssign(ref target, _) = expr.node {
match target.node {
ExprField(ref base, _) |

View File

@ -2,7 +2,7 @@ use rustc::lint::*;
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
use rustc::ty;
use rustc::hir::*;
use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet};
use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet, last_path_segment};
use utils::sugg;
/// **What it does:** Checks for transmutes that can't ever be correct on any
@ -84,11 +84,11 @@ impl LintPass for Transmute {
}
}
impl LateLintPass for Transmute {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprCall(ref path_expr, ref args) = e.node {
if let ExprPath(None, ref path) = path_expr.node {
let def_id = cx.tcx.expect_def(path_expr.id).def_id();
if let ExprPath(ref qpath) = path_expr.node {
let def_id = cx.tcx.tables().qpath_def(qpath, path_expr.id).def_id();
if match_def_path(cx, def_id, &paths::TRANSMUTE) {
let from_ty = cx.tcx.tables().expr_ty(&args[0]);
@ -173,7 +173,7 @@ impl LateLintPass for Transmute {
let arg = if from_pty.ty == to_rty.ty {
arg
} else {
arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, path, to_rty.ty)))
arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_rty.ty)))
};
db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string());
@ -190,9 +190,9 @@ impl LateLintPass for Transmute {
/// Get the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is not available , use
/// the type's `ToString` implementation. In weird cases it could lead to types with invalid `'_`
/// lifetime, but it should be rare.
fn get_type_snippet(cx: &LateContext, path: &Path, to_rty: ty::Ty) -> String {
fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: ty::Ty) -> String {
let seg = last_path_segment(path);
if_let_chain!{[
let Some(seg) = path.segments.last(),
let PathParameters::AngleBracketedParameters(ref ang) = seg.parameters,
let Some(to_ty) = ang.types.get(1),
let TyRptr(_, ref to_ty) = to_ty.node,

View File

@ -1,13 +1,13 @@
use reexport::*;
use rustc::hir::*;
use rustc::hir::intravisit::{FnKind, Visitor, walk_ty};
use rustc::hir::intravisit::{FnKind, Visitor, walk_ty, NestedVisitorMap};
use rustc::lint::*;
use rustc::ty;
use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::codemap::Span;
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet,
span_help_and_lint, span_lint};
span_help_and_lint, span_lint, opt_def_id, last_path_segment};
use utils::paths;
/// Handles all the linting of funky types
@ -69,22 +69,23 @@ impl LintPass for TypePass {
}
}
impl LateLintPass for TypePass {
fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass {
fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ast_ty: &'tcx Ty) {
if in_macro(cx, ast_ty.span) {
return;
}
if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) {
if let def::Def::Struct(..) = did.full_def() {
if Some(did.full_def().def_id()) == cx.tcx.lang_items.owned_box() {
if let TyPath(ref qpath) = ast_ty.node {
let def = cx.tcx.tables().qpath_def(qpath, ast_ty.id);
if let Some(def_id) = opt_def_id(def) {
if Some(def_id) == cx.tcx.lang_items.owned_box() {
let last = last_path_segment(qpath);
if_let_chain! {[
let TyPath(_, ref path) = ast_ty.node,
let Some(ref last) = path.segments.last(),
let PathParameters::AngleBracketedParameters(ref ag) = last.parameters,
let Some(ref vec) = ag.types.get(0),
let Some(did) = cx.tcx.def_map.borrow().get(&vec.id),
let def::Def::Struct(..) = did.full_def(),
match_def_path(cx, did.full_def().def_id(), &paths::VEC),
let TyPath(ref qpath) = vec.node,
let def::Def::Struct(..) = cx.tcx.tables().qpath_def(qpath, vec.id),
let Some(did) = opt_def_id(cx.tcx.tables().qpath_def(qpath, vec.id)),
match_def_path(cx, did, &paths::VEC),
], {
span_help_and_lint(cx,
BOX_VEC,
@ -92,12 +93,12 @@ impl LateLintPass for TypePass {
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
}}
} else if match_def_path(cx, did.full_def().def_id(), &paths::LINKED_LIST) {
} else if match_def_path(cx, def_id, &paths::LINKED_LIST) {
span_help_and_lint(cx,
LINKEDLIST,
ast_ty.span,
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
"a VecDeque might work");
LINKEDLIST,
ast_ty.span,
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
"a VecDeque might work");
}
}
}
@ -152,8 +153,8 @@ impl LintPass for LetPass {
}
}
impl LateLintPass for LetPass {
fn check_decl(&mut self, cx: &LateContext, decl: &Decl) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetPass {
fn check_decl(&mut self, cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl) {
check_let_unit(cx, decl)
}
}
@ -189,8 +190,8 @@ impl LintPass for UnitCmp {
}
}
impl LateLintPass for UnitCmp {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if in_macro(cx, expr.span) {
return;
}
@ -446,8 +447,8 @@ impl LintPass for CastPass {
}
}
impl LateLintPass for CastPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprCast(ref ex, _) = expr.node {
let (cast_from, cast_to) = (cx.tcx.tables().expr_ty(ex), cx.tcx.tables().expr_ty(expr));
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
@ -534,17 +535,17 @@ impl LintPass for TypeComplexityPass {
}
}
impl LateLintPass for TypeComplexityPass {
fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Expr, _: Span, _: NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass {
fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span, _: NodeId) {
self.check_fndecl(cx, decl);
}
fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) {
fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx StructField) {
// enum variants are also struct fields now
self.check_type(cx, &field.ty);
}
fn check_item(&mut self, cx: &LateContext, item: &Item) {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
match item.node {
ItemStatic(ref ty, _, _) |
ItemConst(ref ty, _) => self.check_type(cx, ty),
@ -553,7 +554,7 @@ impl LateLintPass for TypeComplexityPass {
}
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
match item.node {
ConstTraitItem(ref ty, _) |
TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty),
@ -563,7 +564,7 @@ impl LateLintPass for TypeComplexityPass {
}
}
fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
match item.node {
ImplItemKind::Const(ref ty, _) |
ImplItemKind::Type(ref ty) => self.check_type(cx, ty),
@ -572,15 +573,15 @@ impl LateLintPass for TypeComplexityPass {
}
}
fn check_local(&mut self, cx: &LateContext, local: &Local) {
fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
if let Some(ref ty) = local.ty {
self.check_type(cx, ty);
}
}
}
impl TypeComplexityPass {
fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) {
impl<'a, 'tcx> TypeComplexityPass {
fn check_fndecl(&self, cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl) {
for arg in &decl.inputs {
self.check_type(cx, &arg.ty);
}
@ -589,7 +590,7 @@ impl TypeComplexityPass {
}
}
fn check_type(&self, cx: &LateContext, ty: &Ty) {
fn check_type(&self, cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty) {
if in_macro(cx, ty.span) {
return;
}
@ -597,6 +598,7 @@ impl TypeComplexityPass {
let mut visitor = TypeComplexityVisitor {
score: 0,
nest: 1,
cx: cx,
};
visitor.visit_ty(ty);
visitor.score
@ -612,15 +614,16 @@ impl TypeComplexityPass {
}
/// Walks a type and assigns a complexity score to it.
struct TypeComplexityVisitor {
struct TypeComplexityVisitor<'a, 'tcx: 'a> {
/// total complexity score of the type
score: u64,
/// current nesting level
nest: u64,
cx: &'a LateContext<'a, 'tcx>,
}
impl<'v> Visitor<'v> for TypeComplexityVisitor {
fn visit_ty(&mut self, ty: &'v Ty) {
impl<'a, 'tcx: 'a> Visitor<'tcx> for TypeComplexityVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx Ty) {
let (add_score, sub_nest) = match ty.node {
// _, &x and *x have only small overhead; don't mess with nesting level
TyInfer | TyPtr(..) | TyRptr(..) => (1, 0),
@ -645,6 +648,9 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor {
walk_ty(self, ty);
self.nest -= sub_nest;
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}
/// **What it does:** Checks for expressions where a character literal is cast
@ -676,8 +682,8 @@ impl LintPass for CharLitAsU8 {
}
}
impl LateLintPass for CharLitAsU8 {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
use syntax::ast::{LitKind, UintTy};
if let ExprCast(ref e, _) = expr.node {
@ -840,8 +846,8 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
})
}
impl LateLintPass for AbsurdExtremeComparisons {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
use types::ExtremeType::*;
use types::AbsurdComparisonResult::*;
@ -1065,8 +1071,8 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
}
}
impl LateLintPass for InvalidUpcastComparisons {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidUpcastComparisons {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node {
let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);

View File

@ -68,8 +68,8 @@ impl LintPass for Unicode {
}
}
impl LateLintPass for Unicode {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unicode {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprLit(ref lit) = expr.node {
if let LitKind::Str(_, _) = lit.node {
check_str(cx, lit.span)

View File

@ -1,6 +1,5 @@
use rustc::hir::*;
use rustc::lint::*;
use syntax::ast::Name;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::symbol::InternedString;
use utils::span_lint;
@ -34,16 +33,16 @@ impl LintPass for UnsafeNameRemoval {
}
}
impl LateLintPass for UnsafeNameRemoval {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
if let ItemUse(ref item_use) = item.node {
impl EarlyLintPass for UnsafeNameRemoval {
fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
if let ItemKind::Use(ref item_use) = item.node {
match item_use.node {
ViewPath_::ViewPathSimple(ref name, ref path) => {
unsafe_to_safe_check(
path.segments
.last()
.expect("use paths cannot be empty")
.name,
.identifier,
*name,
cx, &item.span
);
@ -62,9 +61,9 @@ impl LateLintPass for UnsafeNameRemoval {
}
}
fn unsafe_to_safe_check(old_name: Name, new_name: Name, cx: &LateContext, span: &Span) {
let old_str = old_name.as_str();
let new_str = new_name.as_str();
fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext, span: &Span) {
let old_str = old_name.name.as_str();
let new_str = new_name.name.as_str();
if contains_unsafe(&old_str) && !contains_unsafe(&new_str) {
span_lint(cx,
UNSAFE_REMOVED_FROM_NAME,

View File

@ -1,6 +1,6 @@
use rustc::lint::*;
use rustc::hir;
use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, NestedVisitorMap};
use std::collections::HashMap;
use syntax::ast;
use syntax::codemap::Span;
@ -29,15 +29,9 @@ declare_lint! {
pub struct UnusedLabel;
#[derive(Default)]
struct UnusedLabelVisitor {
struct UnusedLabelVisitor<'a, 'tcx: 'a> {
labels: HashMap<InternedString, Span>,
}
impl UnusedLabelVisitor {
pub fn new() -> UnusedLabelVisitor {
::std::default::Default::default()
}
cx: &'a LateContext<'a, 'tcx>,
}
impl LintPass for UnusedLabel {
@ -46,14 +40,25 @@ impl LintPass for UnusedLabel {
}
}
impl LateLintPass for UnusedLabel {
fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Expr, span: Span, fn_id: ast::NodeId) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Expr,
span: Span,
fn_id: ast::NodeId,
) {
if in_macro(cx, span) {
return;
}
let mut v = UnusedLabelVisitor::new();
walk_fn(&mut v, kind, decl, body, span, fn_id);
let mut v = UnusedLabelVisitor {
cx: cx,
labels: HashMap::new(),
};
walk_fn(&mut v, kind, decl, body.expr_id(), span, fn_id);
for (label, span) in v.labels {
span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label));
@ -61,12 +66,12 @@ impl LateLintPass for UnusedLabel {
}
}
impl<'v> Visitor<'v> for UnusedLabelVisitor {
fn visit_expr(&mut self, expr: &hir::Expr) {
impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
match expr.node {
hir::ExprBreak(Some(label), _) |
hir::ExprAgain(Some(label)) => {
self.labels.remove(&label.node.as_str());
self.labels.remove(&label.name.as_str());
}
hir::ExprLoop(_, Some(label), _) |
hir::ExprWhile(_, _, Some(label)) => {
@ -77,4 +82,7 @@ impl<'v> Visitor<'v> for UnusedLabelVisitor {
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}

View File

@ -44,19 +44,6 @@ pub struct Range<'a> {
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
pub fn range(expr: &hir::Expr) -> Option<Range> {
/// Skip unstable blocks. To be removed when ranges get stable.
fn unwrap_unstable(expr: &hir::Expr) -> &hir::Expr {
if let hir::ExprBlock(ref block) = expr.node {
if block.rules == hir::BlockCheckMode::PushUnstableBlock || block.rules == hir::BlockCheckMode::PopUnstableBlock {
if let Some(ref expr) = block.expr {
return expr;
}
}
}
expr
}
/// Find the field named `name` in the field. Always return `Some` for convenience.
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
let expr = &fields.iter()
@ -64,14 +51,14 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
.unwrap_or_else(|| panic!("missing {} field for range", name))
.expr;
Some(unwrap_unstable(expr))
Some(expr)
}
// The range syntax is expanded to literal paths starting with `core` or `std` depending on
// `#[no_std]`. Testing both instead of resolving the paths.
match unwrap_unstable(expr).node {
hir::ExprPath(None, ref path) => {
match expr.node {
hir::ExprPath(ref path) => {
if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) {
Some(Range {
start: None,
@ -168,15 +155,15 @@ pub enum VecArgs<'a> {
pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e>> {
if_let_chain!{[
let hir::ExprCall(ref fun, ref args) = expr.node,
let hir::ExprPath(_, ref path) = fun.node,
let Some(fun_def) = resolve_node(cx, fun.id),
let hir::ExprPath(ref path) = fun.node,
is_expn_of(cx, fun.span, "vec").is_some(),
], {
let fun_def = resolve_node(cx, path, fun.id);
return if match_def_path(cx, fun_def.def_id(), &paths::VEC_FROM_ELEM) && args.len() == 2 {
// `vec![elem; size]` case
Some(VecArgs::Repeat(&args[0], &args[1]))
}
else if match_path(path, &["into_vec"]) && args.len() == 1 {
else if match_def_path(cx, fun_def.def_id(), &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
if_let_chain!{[
let hir::ExprBox(ref boxed) = args[0].node,

View File

@ -69,7 +69,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.node, &right.node) {
(&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re),
(&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()),
(&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str()),
(&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
(&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
@ -82,7 +82,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
})
}
(&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) =>
both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str())
both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str())
&& both(le, re, |l, r| self.eq_expr(l, r)),
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
(&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
@ -101,12 +101,13 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
}
(&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
(&ExprLoop(ref lb, ref ll, ref lls), &ExprLoop(ref rb, ref rl, ref rls)) => {
self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) && lls == rls
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
}
(&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
ls == rs && self.eq_expr(le, re) &&
over(la, ra, |l, r| {
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
self.eq_expr(&l.body, &r.body) &&
both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
})
}
@ -118,11 +119,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
}
(&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl),
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref l_qself, ref l_subpath), &ExprPath(ref r_qself, ref r_subpath)) => {
both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath)
}
(&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
self.eq_path(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
over(lf, rf, |l, r| self.eq_field(l, r))
}
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
@ -153,14 +152,12 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.node, &right.node) {
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
self.eq_path(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
}
(&PatKind::Binding(ref lb, ref li, ref lp), &PatKind::Binding(ref rb, ref ri, ref rp)) => {
(&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => {
lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
}
(&PatKind::Path(ref ql, ref l), &PatKind::Path(ref qr, ref r)) => {
both(ql, qr, |ql, qr| self.eq_qself(ql, qr)) && self.eq_path(l, r)
}
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
(&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
@ -178,6 +175,18 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
}
}
fn eq_qpath(&self, left: &QPath, right: &QPath) -> bool {
match (left, right) {
(&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
},
(&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
_ => false,
}
}
fn eq_path(&self, left: &Path, right: &Path) -> bool {
left.global == right.global &&
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
@ -208,10 +217,6 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
self.eq_path_parameters(&left.parameters, &right.parameters)
}
fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool {
left.ty.node == right.ty.node && left.position == right.position
}
fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
match (&left.node, &right.node) {
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
@ -222,9 +227,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
}
(&TyPath(ref lq, ref l_path), &TyPath(ref rq, ref r_path)) => {
both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(l_path, r_path)
}
(&TyPath(ref l), &TyPath(ref r)) => self.eq_qpath(l, r),
(&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
(&TyInfer, &TyInfer) => true,
_ => false,
@ -318,7 +321,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
let c: fn(_) -> _ = ExprAgain;
c.hash(&mut self.s);
if let Some(i) = i {
self.hash_name(&i.node);
self.hash_name(&i.name);
}
}
ExprAssign(ref l, ref r) => {
@ -350,7 +353,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
let c: fn(_, _) -> _ = ExprBreak;
c.hash(&mut self.s);
if let Some(i) = i {
self.hash_name(&i.node);
self.hash_name(&i.name);
}
if let Some(ref j) = *j {
self.hash_expr(&*j);
@ -373,11 +376,11 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
self.hash_expr(e);
// TODO: _ty
}
ExprClosure(cap, _, ref e, _) => {
ExprClosure(cap, _, eid, _) => {
let c: fn(_, _, _, _) -> _ = ExprClosure;
c.hash(&mut self.s);
cap.hash(&mut self.s);
self.hash_expr(e);
self.hash_expr(self.cx.tcx.map.expr(eid));
}
ExprField(ref e, ref f) => {
let c: fn(_, _) -> _ = ExprField;
@ -409,14 +412,13 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
c.hash(&mut self.s);
l.hash(&mut self.s);
}
ExprLoop(ref b, ref i, ref j) => {
ExprLoop(ref b, ref i, _) => {
let c: fn(_, _, _) -> _ = ExprLoop;
c.hash(&mut self.s);
self.hash_block(b);
if let Some(i) = *i {
self.hash_name(&i.node);
}
j.hash(&mut self.s);
}
ExprMatch(ref e, ref arms, ref s) => {
let c: fn(_, _, _) -> _ = ExprMatch;
@ -452,16 +454,16 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
self.hash_expr(e);
}
}
ExprPath(ref _qself, ref subpath) => {
let c: fn(_, _) -> _ = ExprPath;
ExprPath(ref qpath) => {
let c: fn(_) -> _ = ExprPath;
c.hash(&mut self.s);
self.hash_path(subpath);
self.hash_qpath(qpath);
}
ExprStruct(ref path, ref fields, ref expr) => {
let c: fn(_, _, _) -> _ = ExprStruct;
c.hash(&mut self.s);
self.hash_path(path);
self.hash_qpath(path);
for f in fields {
self.hash_name(&f.name.node);
@ -526,6 +528,18 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
n.as_str().hash(&mut self.s);
}
pub fn hash_qpath(&mut self, p: &QPath) {
match *p {
QPath::Resolved(_, ref path) => {
self.hash_path(path);
}
QPath::TypeRelative(_, ref path) => {
self.hash_name(&path.name);
}
}
//self.cx.tcx.tables().qpath_def(p, id).hash(&mut self.s);
}
pub fn hash_path(&mut self, p: &Path) {
p.global.hash(&mut self.s);
for p in &p.segments {

View File

@ -36,15 +36,15 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
if !has_attr(&item.attrs) {
return;
}
print_item(cx, item);
}
fn check_impl_item(&mut self, cx: &LateContext, item: &hir::ImplItem) {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
if !has_attr(&item.attrs) {
return;
}
@ -68,33 +68,33 @@ impl LateLintPass for Pass {
}
}
/*
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
if !has_attr(&item.attrs) {
return;
}
}
fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant, _: &hir::Generics) {
fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: &hir::Generics) {
if !has_attr(&var.node.attrs) {
return;
}
}
fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
if !has_attr(&field.attrs) {
return;
}
}
*/
fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
if !has_attr(&expr.attrs) {
return;
}
print_expr(cx, expr, 0);
}
fn check_arm(&mut self, cx: &LateContext, arm: &hir::Arm) {
fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
if !has_attr(&arm.attrs) {
return;
}
@ -109,7 +109,7 @@ impl LateLintPass for Pass {
print_expr(cx, &arm.body, 1);
}
fn check_stmt(&mut self, cx: &LateContext, stmt: &hir::Stmt) {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
if !has_attr(stmt.node.attrs()) {
return;
}
@ -120,7 +120,7 @@ impl LateLintPass for Pass {
}
/*
fn check_foreign_item(&mut self, cx: &LateContext, item: &hir::ForeignItem) {
fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) {
if !has_attr(&item.attrs) {
return;
}
@ -275,11 +275,14 @@ fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) {
println!("{}index expr:", ind);
print_expr(cx, idx, indent + 1);
},
hir::ExprPath(ref sel, ref path) => {
println!("{}Path, {}", ind, ty);
println!("{}self: {:?}", ind, sel);
hir::ExprPath(hir::QPath::Resolved(ref ty, ref path)) => {
println!("{}Resolved Path, {:?}", ind, ty);
println!("{}path: {:?}", ind, path);
},
hir::ExprPath(hir::QPath::TypeRelative(ref ty, ref seg)) => {
println!("{}Relative Path, {:?}", ind, ty);
println!("{}seg: {:?}", ind, seg);
}
hir::ExprAddrOf(ref muta, ref e) => {
println!("{}AddrOf, {}", ind, ty);
println!("mutability: {:?}", muta);
@ -354,7 +357,7 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
println!("weird extern crate without a crate id");
}
}
hir::ItemUse(ref path) => println!("{:?}", path.node),
hir::ItemUse(ref path, ref kind) => println!("{:?}, {:?}", path, kind),
hir::ItemStatic(..) => println!("static item of type {:#?}", cx.tcx.item_type(did)),
hir::ItemConst(..) => println!("const item of type {:#?}", cx.tcx.item_type(did)),
hir::ItemFn(..) => {
@ -383,13 +386,11 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
println!("trait has no default impl");
}
},
hir::ItemDefaultImpl(_, ref trait_ref) => {
let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id();
println!("default impl for `{}`", cx.tcx.item_path_str(trait_did));
hir::ItemDefaultImpl(_, ref _trait_ref) => {
println!("default impl");
},
hir::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => {
let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id();
println!("impl of trait `{}`", cx.tcx.item_path_str(trait_did));
hir::ItemImpl(_, _, _, Some(ref _trait_ref), _, _) => {
println!("trait impl");
},
hir::ItemImpl(_, _, _, None, _, _) => {
println!("impl");
@ -402,7 +403,7 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) {
println!("{}+", ind);
match pat.node {
hir::PatKind::Wild => println!("{}Wild", ind),
hir::PatKind::Binding(ref mode, ref name, ref inner) => {
hir::PatKind::Binding(ref mode, _, ref name, ref inner) => {
println!("{}Binding", ind);
println!("{}mode: {:?}", ind, mode);
println!("{}name: {}", ind, name.node);
@ -434,11 +435,14 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) {
print_pat(cx, field, indent + 1);
}
},
hir::PatKind::Path(ref sel, ref path) => {
println!("{}Path", ind);
println!("{}self: {:?}", ind, sel);
hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
println!("{}Resolved Path, {:?}", ind, ty);
println!("{}path: {:?}", ind, path);
},
hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
println!("{}Relative Path, {:?}", ind, ty);
println!("{}seg: {:?}", ind, seg);
},
hir::PatKind::Tuple(ref pats, opt_dots_position) => {
println!("{}Tuple", ind);
if let Some(dot_position) = opt_dots_position {

View File

@ -1,6 +1,6 @@
use rustc::lint::*;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_expr};
use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap};
use utils::{paths, match_path, span_lint};
use syntax::symbol::InternedString;
use syntax::ast::{Name, NodeId, ItemKind, Crate as AstCrate};
@ -104,19 +104,19 @@ impl LintPass for LintWithoutLintPass {
}
impl LateLintPass for LintWithoutLintPass {
fn check_item(&mut self, _: &LateContext, item: &Item) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if let ItemStatic(ref ty, MutImmutable, ref expr) = item.node {
if is_lint_ref_type(ty) {
self.declared_lints.insert(item.name, item.span);
} else if is_lint_array_type(ty) && item.vis == Visibility::Inherited && item.name == "ARRAY" {
let mut collector = LintCollector { output: &mut self.registered_lints };
let mut collector = LintCollector { output: &mut self.registered_lints, cx: cx };
collector.visit_expr(expr);
}
}
}
fn check_crate_post(&mut self, cx: &LateContext, _: &Crate) {
fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, _: &'tcx Crate) {
for (lint_name, &lint_span) in &self.declared_lints {
// When using the `declare_lint!` macro, the original `lint_span`'s
// file points to "<rustc macros>".
@ -140,7 +140,7 @@ impl LateLintPass for LintWithoutLintPass {
fn is_lint_ref_type(ty: &Ty) -> bool {
if let TyRptr(Some(_), MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node {
if let TyPath(None, ref path) = inner.node {
if let TyPath(ref path) = inner.node {
return match_path(path, &paths::LINT);
}
}
@ -149,25 +149,29 @@ fn is_lint_ref_type(ty: &Ty) -> bool {
fn is_lint_array_type(ty: &Ty) -> bool {
if let TyPath(None, ref path) = ty.node {
if let TyPath(ref path) = ty.node {
match_path(path, &paths::LINT_ARRAY)
} else {
false
}
}
struct LintCollector<'a> {
struct LintCollector<'a, 'tcx: 'a> {
output: &'a mut HashSet<Name>,
cx: &'a LateContext<'a, 'tcx>,
}
impl<'v, 'a: 'v> Visitor<'v> for LintCollector<'a> {
fn visit_expr(&mut self, expr: &'v Expr) {
impl<'a, 'tcx: 'a> Visitor<'tcx> for LintCollector<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
walk_expr(self, expr);
}
fn visit_path(&mut self, path: &'v Path, _: NodeId) {
fn visit_path(&mut self, path: &'tcx Path, _: NodeId) {
if path.segments.len() == 1 {
self.output.insert(path.segments[0].name);
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.map)
}
}

View File

@ -1,6 +1,7 @@
use reexport::*;
use rustc::hir::*;
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::hir::def::Def;
use rustc::hir::map::Node;
use rustc::lint::{LintContext, LateContext, Level, Lint};
use rustc::session::Session;
@ -93,16 +94,25 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
rhs.expn_id != lhs.expn_id
}
/// Returns true if this `expn_info` was expanded by any macro.
pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some())
pub fn in_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id, |info| match info {
Some(info) => {
match info.callee.format {
// don't treat range expressions desugared to structs as "in_macro"
ExpnFormat::CompilerDesugaring(name) => name != "...",
_ => true,
}
},
None => false,
})
}
/// Returns true if the macro that expanded the crate was outside of the current crate or was a
/// compiler plugin.
pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool {
pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
/// Invokes `in_macro` with the expansion info of the given span slightly heavy, try to use
/// this after other checks have already happened.
fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool {
fn in_macro_ext<'a, T: LintContext<'a>>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool {
// no ExpnInfo = no macro
opt_info.map_or(false, |info| {
if let ExpnFormat::MacroAttribute(..) = info.callee.format {
@ -196,13 +206,44 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool
}
}
pub fn last_path_segment(path: &QPath) -> &PathSegment {
match *path {
QPath::Resolved(_, ref path) => path.segments
.last()
.expect("A path must have at least one segment"),
QPath::TypeRelative(_, ref seg) => seg,
}
}
pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> {
match *path {
QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]),
QPath::Resolved(..) => None,
QPath::TypeRelative(_, ref seg) => Some(seg),
}
}
/// Match a `Path` against a slice of segment string literals.
///
/// # Examples
/// ```
/// match_path(path, &["std", "rt", "begin_unwind"])
/// ```
pub fn match_path(path: &Path, segments: &[&str]) -> bool {
pub fn match_path(path: &QPath, segments: &[&str]) -> bool {
match *path {
QPath::Resolved(_, ref path) => match_path_old(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node {
TyPath(ref inner_path) => {
segments.len() > 0 &&
match_path(inner_path, &segments[..(segments.len() - 1)]) &&
segment.name == segments[segments.len() - 1]
},
_ => false,
},
}
}
pub fn match_path_old(path: &Path, segments: &[&str]) -> bool {
path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name == *b)
}
@ -283,8 +324,8 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>,
}
/// Resolve the definition of a node from its `NodeId`.
pub fn resolve_node(cx: &LateContext, id: NodeId) -> Option<def::Def> {
cx.tcx.def_map.borrow().get(&id).map(|d| d.full_def())
pub fn resolve_node(cx: &LateContext, qpath: &QPath, id: NodeId) -> def::Def {
cx.tcx.tables().qpath_def(qpath, id)
}
/// Match an `Expr` against a chain of methods, and return the matched `Expr`s.
@ -330,12 +371,12 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
/// ```
/// snippet(cx, expr.span, "..")
/// ```
pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default))
}
/// Convert a span to a code snippet. Returns `None` if not available.
pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> {
cx.sess().codemap().span_to_snippet(span).ok()
}
@ -347,14 +388,14 @@ pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
/// ```
/// snippet(cx, expr.span, "..")
/// ```
pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
let snip = snippet(cx, span, default);
trim_multiline(snip, true)
}
/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`.
/// Also takes an `Option<String>` which can be put inside the braces.
pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> {
pub fn expr_block<'a, 'b, T: LintContext<'b>>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> {
let code = snippet_block(cx, expr.span, default);
let string = option.unwrap_or_default();
if let ExprBlock(_) = expr.node {
@ -423,15 +464,15 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> {
})
}
pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> {
pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
let map = &cx.tcx.map;
let enclosing_node = map.get_enclosing_scope(node)
.and_then(|enclosing_id| map.find(enclosing_id));
if let Some(node) = enclosing_node {
match node {
Node::NodeBlock(block) => Some(block),
Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref expr), .. }) => {
match expr.node {
Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, eid), .. }) => {
match cx.tcx.map.expr(eid).node {
ExprBlock(ref block) => Some(block),
_ => None,
}
@ -460,15 +501,14 @@ impl<'a> DiagnosticWrapper<'a> {
}
}
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) {
pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
if cx.current_level(lint) != Level::Allow {
db.wiki_link(lint);
}
}
// FIXME: needless lifetime doesn't trigger here
pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
if cx.current_level(lint) != Level::Allow {
db.0.help(help);
@ -476,8 +516,14 @@ pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp
}
}
pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span,
note: &str) {
pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
cx: &'a T,
lint: &'static Lint,
span: Span,
msg: &str,
note_span: Span,
note: &str,
) {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
if cx.current_level(lint) != Level::Allow {
if note_span == span {
@ -489,8 +535,8 @@ pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp
}
}
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where F: FnOnce(&mut DiagnosticBuilder<'a>)
pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>)
{
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
if cx.current_level(lint) != Level::Allow {
@ -705,7 +751,7 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T
let fn_def_id = cx.tcx.map.local_def_id(fn_item);
let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig();
let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, fn_sig);
fn_sig.output
fn_sig.output()
}
/// Check if two types are the same.
@ -736,8 +782,8 @@ pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, env: Node
/// Return whether a pattern is refutable.
pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
fn is_enum_variant(cx: &LateContext, did: NodeId) -> bool {
matches!(cx.tcx.def_map.borrow().get(&did).map(|d| d.full_def()), Some(def::Def::Variant(..)) | Some(def::Def::VariantCtor(..)))
fn is_enum_variant(cx: &LateContext, qpath: &QPath, did: NodeId) -> bool {
matches!(cx.tcx.tables().qpath_def(qpath, did), def::Def::Variant(..) | def::Def::VariantCtor(..))
}
fn are_refutable<'a, I: Iterator<Item=&'a Pat>>(cx: &LateContext, mut i: I) -> bool {
@ -748,17 +794,17 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
PatKind::Binding(..) | PatKind::Wild => false,
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
PatKind::Lit(..) | PatKind::Range(..) => true,
PatKind::Path(..) => is_enum_variant(cx, pat.id),
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.id),
PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
PatKind::Struct(_, ref fields, _) => {
if is_enum_variant(cx, pat.id) {
PatKind::Struct(ref qpath, ref fields, _) => {
if is_enum_variant(cx, qpath, pat.id) {
true
} else {
are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
}
}
PatKind::TupleStruct(_, ref pats, _) => {
if is_enum_variant(cx, pat.id) {
PatKind::TupleStruct(ref qpath, ref pats, _) => {
if is_enum_variant(cx, qpath, pat.id) {
true
} else {
are_refutable(cx, pats.iter().map(|pat| &**pat))
@ -793,3 +839,20 @@ pub fn remove_blocks(expr: &Expr) -> &Expr {
expr
}
}
pub fn opt_def_id(def: Def) -> Option<DefId> {
match def {
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
Some(id)
}
Def::Label(..) |
Def::PrimTy(..) |
Def::SelfTy(..) |
Def::Err => None,
}
}

View File

@ -12,7 +12,7 @@ pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"];
pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"];
pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"];
pub const CSTRING_NEW: [&'static str; 5] = ["std", "ffi", "c_str", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Display", "fmt"];
@ -64,6 +64,7 @@ pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&'static str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&'static str; 4] = ["core", "result", "Result", "Ok"];
pub const SERDE_DE_VISITOR: [&'static str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&'static str; 4] = ["collections", "slice", "<impl [T]>", "into_vec"];
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];

View File

@ -384,7 +384,7 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
}
/// Return the indentation before `span` if there are nothing but `[ \t]` before it on its line.
fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> {
let lo = cx.sess().codemap().lookup_char_pos(span.lo);
if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) {
if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
@ -403,7 +403,7 @@ fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
}
/// Convenience extension trait for `DiagnosticBuilder`.
pub trait DiagnosticBuilderExt<T: LintContext> {
pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
/// Suggests to add an attribute to an item.
///
/// Correctly handles indentation of the attribute and item.
@ -430,7 +430,7 @@ pub trait DiagnosticBuilderExt<T: LintContext> {
fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str);
}
impl<'a, 'b, T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'b> {
impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
fn suggest_item_with_attr<D: Display+?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D) {
if let Some(indent) = indentation(cx, item) {
let span = Span {

View File

@ -32,8 +32,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// search for `&vec![_]` expressions where the adjusted type is `&[_]`
if_let_chain!{[
let ty::TypeVariants::TyRef(_, ref ty) = cx.tcx.tables().expr_ty_adjusted(expr).sty,

View File

@ -27,8 +27,8 @@ impl LintPass for Pass {
}
}
impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// check for instances of 0.0/0.0
if_let_chain! {[
let ExprBinary(ref op, ref left, ref right) = expr.node,

View File

@ -9,6 +9,7 @@
#![allow(blacklisted_name)]
#![allow(collapsible_if)]
#![allow(zero_divided_by_zero, eq_op)]
#![allow(path_statements)]
fn bar<T>(_: T) {}
fn foo() -> bool { unimplemented!() }
@ -236,6 +237,13 @@ fn if_same_then_else() -> Result<&'static str, ()> {
if let Some(42) = None {}
}
if true {
if let Some(42) = None::<u8> {}
}
else {
if let Some(42) = None::<u32> {}
}
if true {
if let Some(a) = Some(42) {}
}

View File

@ -10,5 +10,5 @@ pub fn test(_: LinkedList<u8>) { //~ ERROR I see you're using a LinkedList!
}
fn main(){
test(LinkedList::new());
test(LinkedList::new()); //~ ERROR I see you're using a LinkedList!
}