Merge branch 'master' into never_loop

This commit is contained in:
Cameron Steffen 2017-06-11 18:25:26 -05:00
commit 8b00f826d7
46 changed files with 427 additions and 408 deletions

View file

@ -1,25 +1,36 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.0.136 - 2017-05-26
## 0.0.139 — 2017-06-10
* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
* Fix bugs with for loop desugaring
* Check for AsRef/AsMut arguments in wrong_self_convention
## 0.0.138 — 2017-06-05
* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
## 0.0.137 — 2017-06-05
* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
## 0.0.136 — 2017—05—26
* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
## 0.0.135 - 2017-05-24
## 0.0.135 — 2017—05—24
* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
## 0.0.134 - 2017-05-19
## 0.0.134 — 2017—05—19
* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
## 0.0.133 - 2017-05-14
## 0.0.133 — 2017—05—14
* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
## 0.0.132 - 2017-05-05
## 0.0.132 — 2017—05—05
* Fix various bugs and some ices
## 0.0.131 - 2017-05-04
## 0.0.131 — 2017—05—04
* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
## 0.0.130 - 2017-05-03
## 0.0.130 — 2017—05—03
* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
## 0.0.129 — 2017-05-01

View file

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

View file

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

View file

@ -82,14 +82,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
if let hir::ExprBinary(binop, ref l, ref r) = rhs.node {
if op.node == binop.node {
let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
let ty = cx.tables.expr_ty(assignee);
if ty.walk_shallow().next().is_some() {
return; // implements_trait does not work with generics
}
let rty = cx.tables.expr_ty(rhs);
if rty.walk_shallow().next().is_some() {
return; // implements_trait does not work with generics
}
span_lint_and_then(cx,
MISREFACTORED_ASSIGN_OP,
expr.span,
@ -120,13 +112,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
#[allow(cyclomatic_complexity)]
let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
let ty = cx.tables.expr_ty(assignee);
if ty.walk_shallow().next().is_some() {
return; // implements_trait does not work with generics
}
let rty = cx.tables.expr_ty(rhs);
if rty.walk_shallow().next().is_some() {
return; // implements_trait does not work with generics
}
macro_rules! ops {
($op:expr,
$cx:expr,
@ -152,7 +138,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
let hir::Item_::ItemImpl(_, _, _, _, Some(ref trait_ref), _, _) = item.node,
trait_ref.path.def.def_id() == trait_id
], { return; }}
implements_trait($cx, $ty, trait_id, &[$rty], None)
implements_trait($cx, $ty, trait_id, &[$rty])
},)*
_ => false,
}

View file

@ -3,7 +3,7 @@
use reexport::*;
use rustc::lint::*;
use rustc::hir::*;
use rustc::ty;
use rustc::ty::{self, TyCtxt};
use semver::Version;
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
@ -158,7 +158,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
}
}
fn is_relevant_item(tcx: ty::TyCtxt, item: &Item) -> bool {
fn is_relevant_item(tcx: TyCtxt, item: &Item) -> bool {
if let ItemFn(_, _, _, _, _, eid) = item.node {
is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
} else {
@ -166,14 +166,14 @@ fn is_relevant_item(tcx: ty::TyCtxt, item: &Item) -> bool {
}
}
fn is_relevant_impl(tcx: ty::TyCtxt, item: &ImplItem) -> bool {
fn is_relevant_impl(tcx: TyCtxt, item: &ImplItem) -> bool {
match item.node {
ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value),
_ => false,
}
}
fn is_relevant_trait(tcx: ty::TyCtxt, item: &TraitItem) -> bool {
fn is_relevant_trait(tcx: TyCtxt, item: &TraitItem) -> bool {
match item.node {
TraitItemKind::Method(_, TraitMethod::Required(_)) => true,
TraitItemKind::Method(_, TraitMethod::Provided(eid)) => {
@ -183,7 +183,7 @@ fn is_relevant_trait(tcx: ty::TyCtxt, item: &TraitItem) -> bool {
}
}
fn is_relevant_block(tcx: ty::TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool {
fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool {
if let Some(stmt) = block.stmts.first() {
match stmt.node {
StmtDecl(_, _) => true,
@ -195,7 +195,7 @@ fn is_relevant_block(tcx: ty::TyCtxt, tables: &ty::TypeckTables, block: &Block)
}
}
fn is_relevant_expr(tcx: ty::TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool {
fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool {
match expr.node {
ExprBlock(ref block) => is_relevant_block(tcx, tables, block),
ExprRet(Some(ref e)) => is_relevant_expr(tcx, tables, e),

View file

@ -385,10 +385,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
e.span,
"this boolean expression can be simplified",
|db| {
db.span_suggestions(e.span, "try", improvements.into_iter().map(|suggestion| {
suggest(self.cx, suggestion, &h2q.terminals)
}).collect());
});
db.span_suggestions(e.span,
"try",
improvements.into_iter()
.map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals))
.collect());
});
}
}
}

View file

@ -5,7 +5,7 @@ use rustc::hir::def::Def;
use rustc_const_eval::lookup_const_by_id;
use rustc_const_math::ConstInt;
use rustc::hir::*;
use rustc::ty::{self, TyCtxt};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::ty::subst::{Substs, Subst};
use std::cmp::Ordering::{self, Equal};
use std::cmp::PartialOrd;
@ -161,7 +161,7 @@ impl PartialOrd for Constant {
/// parse a `LitKind` to a `Constant`
#[allow(cast_possible_wrap)]
pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut ty: ty::Ty<'tcx>) -> Constant {
pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut ty: Ty<'tcx>) -> Constant {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
use rustc::ty::util::IntTypeExt;
@ -286,9 +286,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
match def {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
let substs = self.tables
.node_id_item_substs(id)
.unwrap_or_else(|| self.tcx.intern_substs(&[]));
let substs = self.tables.node_substs(id);
let substs = if self.substs.is_empty() {
substs
} else {

View file

@ -1,5 +1,5 @@
use rustc::lint::*;
use rustc::ty;
use rustc::ty::Ty;
use rustc::hir::*;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
@ -251,12 +251,8 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) {
}
/// Return the list of bindings in a pattern.
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> {
fn bindings_impl<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &Pat,
map: &mut HashMap<InternedString, ty::Ty<'tcx>>
) {
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, Ty<'tcx>> {
fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, Ty<'tcx>>) {
match pat.node {
PatKind::Box(ref pat) |
PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),

View file

@ -1,6 +1,5 @@
use rustc::lint::*;
use rustc::ty::TypeVariants;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::hir::*;
use syntax::codemap::Span;
use utils::paths;
@ -89,7 +88,7 @@ fn check_hash_peq<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
span: Span,
trait_ref: &TraitRef,
ty: ty::Ty<'tcx>,
ty: Ty<'tcx>,
hash_is_automatically_derived: bool
) {
if_let_chain! {[
@ -134,28 +133,27 @@ fn check_hash_peq<'a, 'tcx>(
}
/// 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>) {
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: Ty<'tcx>) {
if match_path_old(&trait_ref.path, &paths::CLONE_TRAIT) {
let def_id = cx.tcx.hir.local_def_id(item.id);
if !is_copy(cx, ty, def_id) {
if !is_copy(cx, ty) {
return;
}
match ty.sty {
TypeVariants::TyAdt(def, _) if def.is_union() => return,
ty::TyAdt(def, _) if def.is_union() => return,
// Some types are not Clone by default but could be cloned “by hand” if necessary
TypeVariants::TyAdt(def, substs) => {
ty::TyAdt(def, substs) => {
for variant in &def.variants {
for field in &variant.fields {
match field.ty(cx.tcx, substs).sty {
TypeVariants::TyArray(_, size) if size > 32 => {
ty::TyArray(_, size) if size > 32 => {
return;
},
TypeVariants::TyFnPtr(..) => {
ty::TyFnPtr(..) => {
return;
},
TypeVariants::TyTuple(tys, _) if tys.len() > 12 => {
ty::TyTuple(tys, _) if tys.len() > 12 => {
return;
},
_ => (),

View file

@ -135,8 +135,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
expr.span,
&msg,
arg.span,
&format!("argument has type {}", arg_ty.sty));
} else if is_copy(cx, arg_ty, cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(arg.id))) {
&format!("argument has type {}", arg_ty));
} else if is_copy(cx, arg_ty) {
if match_def_path(cx.tcx, def_id, &paths::DROP) {
lint = DROP_COPY;
msg = DROP_COPY_SUMMARY.to_string();
@ -151,7 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
expr.span,
&msg,
arg.span,
&format!("argument has type {}", arg_ty.sty));
&format!("argument has type {}", arg_ty));
}
}}
}

View file

@ -36,7 +36,7 @@ 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));
self.lint_item(cx, cx.tcx.hir.expect_item(item.id));
}
}
}

View file

@ -75,8 +75,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
BiNe | BiEq => (cx.tcx.lang_items.eq_trait(), true),
BiLt | BiLe | BiGe | BiGt => (cx.tcx.lang_items.ord_trait(), true),
};
let parent = cx.tcx.hir.get_parent(e.id);
let parent = cx.tcx.hir.local_def_id(parent);
if let Some(trait_id) = trait_id {
#[allow(match_same_arms)]
match (&left.node, &right.node) {
@ -87,10 +85,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
(&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => {
let lty = cx.tables.expr_ty(l);
let rty = cx.tables.expr_ty(r);
let lcpy = is_copy(cx, lty, parent);
let rcpy = is_copy(cx, rty, parent);
let lcpy = is_copy(cx, lty);
let rcpy = is_copy(cx, rty);
// either operator autorefs or both args are copyable
if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty], None) {
if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty]) {
span_lint_and_then(cx,
OP_REF,
e.span,
@ -100,17 +98,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
let rsnip = snippet(cx, r.span, "...").to_string();
multispan_sugg(db,
"use the values directly".to_string(),
vec![(left.span, lsnip),
(right.span, rsnip)]);
vec![(left.span, lsnip), (right.span, rsnip)]);
})
} else if lcpy && !rcpy &&
implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)], None) {
} else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion(left.span, "use the left value directly", lsnip);
})
} else if !lcpy && rcpy &&
implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty], None) {
} else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
span_lint_and_then(cx,
OP_REF,
e.span,
@ -124,9 +119,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
// &foo == bar
(&ExprAddrOf(_, ref l), _) => {
let lty = cx.tables.expr_ty(l);
let lcpy = is_copy(cx, lty, parent);
if (requires_ref || lcpy) &&
implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)], None) {
let lcpy = is_copy(cx, lty);
if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion(left.span, "use the left value directly", lsnip);
@ -136,9 +130,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
// foo == &bar
(_, &ExprAddrOf(_, ref r)) => {
let rty = cx.tables.expr_ty(r);
let rcpy = is_copy(cx, rty, parent);
if (requires_ref || rcpy) &&
implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty], None) {
let rcpy = is_copy(cx, rty);
if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
let rsnip = snippet(cx, r.span, "...").to_string();
db.span_suggestion(right.span, "use the right value directly", rsnip);

View file

@ -4,13 +4,11 @@ use rustc::hir::map::Node::{NodeExpr, NodeStmt};
use rustc::lint::*;
use rustc::middle::expr_use_visitor::*;
use rustc::middle::mem_categorization::{cmt, Categorization};
use rustc::ty;
use rustc::ty::layout::TargetDataLayout;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty};
use rustc::util::nodemap::NodeSet;
use syntax::ast::NodeId;
use syntax::codemap::Span;
use utils::span_lint;
use utils::{span_lint, type_size};
pub struct Pass {
pub too_large_for_stack: u64,
@ -39,15 +37,13 @@ declare_lint! {
"using `Box<T>` where unnecessary"
}
fn is_non_trait_box(ty: ty::Ty) -> bool {
fn is_non_trait_box(ty: Ty) -> bool {
ty.is_box() && !ty.boxed_ty().is_trait()
}
struct EscapeDelegate<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
set: NodeSet,
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
target: TargetDataLayout,
too_large_for_stack: u64,
}
@ -67,23 +63,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
_: Span,
node_id: NodeId
) {
// we store the infcx because it is expensive to recreate
// the context each time.
let fn_def_id = cx.tcx.hir.local_def_id(node_id);
let mut v = EscapeDelegate {
cx: cx,
set: NodeSet(),
tcx: cx.tcx,
tables: cx.tables,
target: TargetDataLayout::parse(cx.sess()),
too_large_for_stack: self.too_large_for_stack,
};
let infcx = cx.tcx.borrowck_fake_infer_ctxt(body.id());
let fn_def_id = cx.tcx.hir.local_def_id(node_id);
let region_maps = &cx.tcx.region_maps(fn_def_id);
{
let mut vis = ExprUseVisitor::new(&mut v, region_maps, &infcx);
vis.consume_body(body);
}
ExprUseVisitor::new(&mut v, cx.tcx, cx.param_env, region_maps, cx.tables).consume_body(body);
for node in v.set {
span_lint(cx,
@ -94,20 +82,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
}
impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) {
if let Categorization::Local(lid) = cmt.cat {
if self.set.contains(&lid) {
if let Move(DirectRefMove) = mode {
// moved out or in. clearly can't be localized
self.set.remove(&lid);
}
if let Move(DirectRefMove) = mode {
// moved out or in. clearly can't be localized
self.set.remove(&lid);
}
}
}
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {}
fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) {
let map = &self.tcx.hir;
let map = &self.cx.tcx.hir;
if map.is_argument(consume_pat.id) {
// Skip closure arguments
if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) {
@ -147,51 +133,24 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
fn borrow(
&mut self,
borrow_id: NodeId,
_: Span,
cmt: cmt<'tcx>,
_: ty::Region,
_: ty::BorrowKind,
loan_cause: LoanCause
) {
use rustc::ty::adjustment::Adjust;
fn borrow(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, loan_cause: LoanCause) {
if let Categorization::Local(lid) = cmt.cat {
if self.set.contains(&lid) {
if let Some(&Adjust::DerefRef { autoderefs, .. }) =
self.tables
.adjustments
.get(&borrow_id)
.map(|a| &a.kind) {
if LoanCause::AutoRef == loan_cause {
// x.foo()
if autoderefs == 0 {
self.set.remove(&lid); // Used without autodereffing (i.e. x.clone())
}
} else {
span_bug!(cmt.span, "Unknown adjusted AutoRef");
}
} else if LoanCause::AddrOf == loan_cause {
// &x
if let Some(&Adjust::DerefRef { autoderefs, .. }) =
self.tables
.adjustments
.get(&self.tcx
.hir
.get_parent_node(borrow_id))
.map(|a| &a.kind) {
if autoderefs <= 1 {
// foo(&x) where no extra autoreffing is happening
self.set.remove(&lid);
}
}
match loan_cause {
// x.foo()
// Used without autodereffing (i.e. x.clone())
LoanCause::AutoRef |
} else if LoanCause::MatchDiscriminant == loan_cause {
self.set.remove(&lid); // `match x` can move
// &x
// foo(&x) where no extra autoreffing is happening
LoanCause::AddrOf |
// `match x` can move
LoanCause::MatchDiscriminant => {
self.set.remove(&lid);
}
// do nothing for matches, etc. These can't escape
_ => {}
}
}
}
@ -199,18 +158,12 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {}
}
impl<'a, 'tcx: 'a> EscapeDelegate<'a, 'tcx> {
fn is_large_box(&self, ty: ty::Ty<'tcx>) -> bool {
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
// Large types need to be boxed to avoid stack
// overflows.
if ty.is_box() {
let inner = ty.boxed_ty();
self.tcx.infer_ctxt((), Reveal::All).enter(|infcx| if let Ok(layout) = inner.layout(&infcx) {
let size = layout.size(&self.target);
size.bytes() > self.too_large_for_stack
} else {
false
})
type_size(self.cx, ty.boxed_ty()).unwrap_or(0) > self.too_large_for_stack
} else {
false
}

View file

@ -137,11 +137,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
}
},
ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(e.id);
let borrowed_table = self.cx.tables;
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.cx.tcx.erase_late_bound_regions(&result_ty).sty {
if borrowed_table.expr_ty(e).is_never() {
self.report_diverging_sub_expr(e);
}
},

View file

@ -1,7 +1,7 @@
use rustc::hir::*;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::*;
use rustc::ty::TypeVariants;
use rustc::ty;
use syntax::ast::LitKind;
use syntax::symbol::InternedString;
use utils::paths;
@ -132,7 +132,7 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
], {
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
return ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING);
}}
false

View file

@ -1,6 +1,5 @@
use rustc::hir::intravisit;
use rustc::hir;
use rustc::ty;
use rustc::lint::*;
use std::collections::HashSet;
use syntax::ast;
@ -184,8 +183,8 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
}
},
hir::ExprMethodCall(_, _, ref args) => {
let method_call = ty::MethodCall::expr(expr.id);
let base_type = self.cx.tables.method_map[&method_call].ty;
let def_id = self.cx.tables.type_dependent_defs[&expr.id].def_id();
let base_type = self.cx.tcx.type_of(def_id);
if type_is_unsafe_function(base_type) {
for arg in args {

View file

@ -58,14 +58,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {
}
}
#[allow(cast_possible_wrap)]
fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) {
if let Some(Constant::Int(v)) = constant_simple(cx, e) {
if match m {
0 => v.to_u128_unchecked() == 0,
-1 => match v.int_type() {
SignedInt(_) => #[allow(cast_possible_wrap)] (v.to_u128_unchecked() as i128 == -1),
UnsignedInt(_) => false
-1 => {
match v.int_type() {
SignedInt(_) => (v.to_u128_unchecked() as i128 == -1),
UnsignedInt(_) => false,
}
},
1 => v.to_u128_unchecked() == 1,
_ => unreachable!(),

View file

@ -95,7 +95,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef]
{
let did = cx.tcx.hir.local_def_id(item.id.node_id);
let impl_ty = cx.tcx.type_of(did);
impl_ty.fn_args().skip_binder().len() == 1
impl_ty.fn_sig().inputs().skip_binder().len() == 1
}
} else {
false
@ -122,7 +122,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) {
{
let did = cx.tcx.hir.local_def_id(item.id.node_id);
let impl_ty = cx.tcx.type_of(did);
impl_ty.fn_args().skip_binder().len() == 1
impl_ty.fn_sig().inputs().skip_binder().len() == 1
}
} else {
false

View file

@ -7,7 +7,8 @@ use rustc::hir::map::Node::NodeBlock;
use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::middle::region::CodeExtent;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::ty::subst::Subst;
use rustc_const_eval::ConstContext;
use std::collections::HashMap;
use syntax::ast;
@ -739,13 +740,11 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) {
lint_iter_method(cx, args, arg, &method_name);
}
} else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
let method_call = ty::MethodCall::expr(arg.id);
let fn_ty = cx.tables
.method_map
.get(&method_call)
.map(|method_callee| method_callee.ty)
.expect("method calls need an entry in the method map");
let fn_arg_tys = fn_ty.fn_args();
let def_id = cx.tables.type_dependent_defs[&arg.id].def_id();
let substs = cx.tables.node_substs(arg.id);
let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
let fn_arg_tys = method_type.fn_sig().inputs();
assert_eq!(fn_arg_tys.skip_binder().len(), 1);
if fn_arg_tys.skip_binder()[0].is_region_ptr() {
lint_iter_method(cx, args, arg, &method_name);
@ -1049,7 +1048,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool {
match_type(cx, ty, &paths::BTREESET)
}
fn is_iterable_array(ty: ty::Ty) -> bool {
fn is_iterable_array(ty: Ty) -> bool {
// IntoIterator is currently only implemented for array sizes <= 32 in rustc
match ty.sty {
ty::TyArray(_, 0...32) => true,

View file

@ -2,8 +2,8 @@ use rustc::lint::*;
use rustc::hir::*;
use rustc::ty;
use syntax::ast;
use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet, span_help_and_lint,
walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats};
use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet,
span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats};
/// **What it does:** Checks for mapping `clone()` over an iterator.
///

View file

@ -1,7 +1,7 @@
use rustc::hir::*;
use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc_const_eval::ConstContext;
use rustc_const_math::ConstInt;
use std::cmp::Ordering;
@ -226,14 +226,7 @@ fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm],
});
}
fn check_single_match_opt_like(
cx: &LateContext,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
ty: ty::Ty,
els: Option<&Expr>
) {
fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty, els: Option<&Expr>) {
// list of candidate Enums we know will never get any more members
let candidates = &[(&paths::COW, "Borrowed"),
(&paths::COW, "Cow::Borrowed"),

View file

@ -1,7 +1,7 @@
use rustc::hir;
use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::hir::def::Def;
use rustc_const_eval::ConstContext;
use std::borrow::Cow;
@ -10,7 +10,7 @@ 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, last_path_segment, single_segment_path,
match_def_path, is_self, is_self_ty, iter_input_pats};
match_def_path, is_self, is_self_ty, iter_input_pats, match_path_old};
use utils::paths;
use utils::sugg;
@ -649,7 +649,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if name == method_name &&
sig.decl.inputs.len() == n_args &&
out_type.matches(&sig.decl.output) &&
self_kind.matches(first_arg_ty, first_arg, self_ty, false) {
self_kind.matches(first_arg_ty, first_arg, self_ty, false, &sig.generics) {
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
"defining a method called `{}` on this type; consider implementing \
the `{}` trait or choosing a less ambiguous name", name, trait_name));
@ -659,11 +659,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// check conventions w.r.t. conversion method names and predicates
let def_id = cx.tcx.hir.local_def_id(item.id);
let ty = cx.tcx.type_of(def_id);
let is_copy = is_copy(cx, ty, def_id);
let is_copy = is_copy(cx, ty);
for &(ref conv, self_kinds) in &CONVENTIONS {
if_let_chain! {[
conv.check(&name.as_str()),
!self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy)),
!self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &sig.generics)),
], {
let lint = if item.vis == hir::Visibility::Public {
WRONG_PUB_SELF_CONVENTION
@ -684,9 +684,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
let ret_ty = return_ty(cx, implitem.id);
let implitem_defid = cx.tcx.hir.local_def_id(implitem.id);
if name == "new" &&
!ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem_defid)) {
!ret_ty.walk().any(|t| same_tys(cx, t, ty)) {
span_lint(cx,
NEW_RET_NO_SELF,
implitem.span,
@ -725,7 +724,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
return false;
};
if implements_trait(cx, arg_ty, default_trait_id, &[], None) {
if implements_trait(cx, arg_ty, default_trait_id, &[]) {
span_lint_and_then(cx,
OR_FUN_CALL,
span,
@ -820,9 +819,8 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
}
/// Checks for the `CLONE_ON_COPY` lint.
fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_ty: ty::Ty) {
fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty) {
let ty = cx.tables.expr_ty(expr);
let parent = cx.tcx.hir.get_parent(expr.id);
if let ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) = arg_ty.sty {
if let ty::TyRef(..) = inner.sty {
span_lint_and_then(cx,
@ -839,7 +837,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t
}
}
if is_copy(cx, ty, cx.tcx.hir.local_def_id(parent)) {
if is_copy(cx, ty) {
span_lint_and_then(cx,
CLONE_ON_COPY,
expr.span,
@ -979,8 +977,8 @@ fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr) {
}
}
fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option<sugg::Sugg<'static>> {
fn may_slice(cx: &LateContext, ty: ty::Ty) -> bool {
fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: Ty) -> Option<sugg::Sugg<'static>> {
fn may_slice(cx: &LateContext, ty: Ty) -> bool {
match ty.sty {
ty::TySlice(_) => true,
ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
@ -1253,7 +1251,7 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr)
}
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> {
fn get_error_type<'a>(cx: &LateContext, ty: Ty<'a>) -> Option<Ty<'a>> {
if let ty::TyAdt(_, substs) = ty.sty {
if match_type(cx, ty, &paths::RESULT) {
substs.types().nth(1)
@ -1266,9 +1264,9 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> {
}
/// This checks whether a given type is known to implement Debug.
fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
fn has_debug_impl<'a, 'b>(ty: Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
match cx.tcx.lang_items.debug_trait() {
Some(debug) => implements_trait(cx, ty, debug, &[], None),
Some(debug) => implements_trait(cx, ty, debug, &[]),
None => false,
}
}
@ -1353,7 +1351,14 @@ enum SelfKind {
}
impl SelfKind {
fn matches(self, ty: &hir::Ty, arg: &hir::Arg, self_ty: &hir::Ty, allow_value_for_ref: bool) -> bool {
fn matches(
self,
ty: &hir::Ty,
arg: &hir::Arg,
self_ty: &hir::Ty,
allow_value_for_ref: bool,
generics: &hir::Generics
) -> bool {
// Self types in the HIR are desugared to explicit self types. So it will always be `self:
// SomeType`,
// where SomeType can be `Self` or an explicit impl self type (e.g. `Foo` if the impl is on `Foo`)
@ -1384,7 +1389,12 @@ impl SelfKind {
_ => false,
}
} else {
self == SelfKind::No
match self {
SelfKind::Value => false,
SelfKind::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASREF_TRAIT),
SelfKind::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASMUT_TRAIT),
SelfKind::No => true,
}
}
}
@ -1398,6 +1408,44 @@ impl SelfKind {
}
}
fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
single_segment_ty(ty).map_or(false, |seg| {
generics.ty_params.iter().any(|param| {
param.name == seg.name &&
param.bounds.iter().any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path;
match_path_old(path, name) &&
path.segments.last().map_or(false, |s| if let hir::PathParameters::AngleBracketedParameters(ref data) =
s.parameters {
data.types.len() == 1 && (is_self_ty(&data.types[0]) || is_ty(&*data.types[0], self_ty))
} else {
false
})
} else {
false
})
})
})
}
fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool {
match (&ty.node, &self_ty.node) {
(&hir::TyPath(hir::QPath::Resolved(_, ref ty_path)),
&hir::TyPath(hir::QPath::Resolved(_, ref self_ty_path))) => {
ty_path.segments.iter().map(|seg| seg.name).eq(self_ty_path.segments.iter().map(|seg| seg.name))
},
_ => false,
}
}
fn single_segment_ty(ty: &hir::Ty) -> Option<&hir::PathSegment> {
if let hir::TyPath(ref path) = ty.node {
single_segment_path(path)
} else {
None
}
}
impl Convention {
fn check(&self, other: &str) -> bool {
match *self {

View file

@ -455,13 +455,13 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) {
// *arg impls PartialEq<other>
if !arg_ty
.builtin_deref(true, ty::LvaluePreference::NoPreference)
.map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty], None))
.map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty]))
// arg impls PartialEq<*other>
&& !other_ty
.builtin_deref(true, ty::LvaluePreference::NoPreference)
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty], None))
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty]))
// arg impls PartialEq<other>
&& !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty], None) {
&& !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty]) {
return;
}
@ -514,13 +514,13 @@ fn in_attributes_expansion(expr: &Expr) -> bool {
/// Test whether `def` is a variable defined outside a macro.
fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
match *def {
def::Def::Local(id) |
def::Def::Upvar(id, _, _) => {
if let Some(span) = cx.tcx.hir.span_if_local(id) {
!in_macro(span)
} else {
true
}
def::Def::Local(def_id) |
def::Def::Upvar(def_id, _, _) => {
let id = cx.tcx
.hir
.as_local_node_id(def_id)
.expect("local variables should be found in the same crate");
!in_macro(cx.tcx.hir.span(id))
},
_ => false,
}

View file

@ -1,7 +1,7 @@
use rustc::hir;
use rustc::hir::intravisit;
use rustc::lint::*;
use rustc::ty::{TypeAndMut, TyRef};
use rustc::ty;
use utils::{higher, in_external_macro, span_lint};
/// **What it does:** Checks for instances of `mut mut` references.
@ -68,7 +68,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
MUT_MUT,
expr.span,
"generally you want to avoid `&mut &mut _` if possible");
} else if let TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tables.expr_ty(e).sty {
} else if let ty::TyRef(_, ty::TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tables.expr_ty(e).sty {
span_lint(self.cx,
MUT_MUT,
expr.span,

View file

@ -1,5 +1,6 @@
use rustc::lint::*;
use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS};
use rustc::ty::{self, Ty};
use rustc::ty::subst::Subst;
use rustc::hir::*;
use utils::span_lint;
@ -34,44 +35,40 @@ impl LintPass for UnnecessaryMutPassed {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
let borrowed_table = cx.tables;
match e.node {
ExprCall(ref fn_expr, ref arguments) => {
let function_type = borrowed_table.node_types
.get(&fn_expr.id)
.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 {
check_arguments(cx,
arguments,
function_type,
cx.tables.expr_ty(fn_expr),
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)));
}
},
ExprMethodCall(ref name, _, ref arguments) => {
let method_call = MethodCall::expr(e.id);
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
check_arguments(cx, arguments, method_type.ty, &name.node.as_str())
let def_id = cx.tables.type_dependent_defs[&e.id].def_id();
let substs = cx.tables.node_substs(e.id);
let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
check_arguments(cx, arguments, method_type, &name.node.as_str())
},
_ => (),
}
}
}
fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS, name: &str) {
fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: Ty, name: &str) {
match type_definition.sty {
TypeVariants::TyFnDef(_, _, fn_type) |
TypeVariants::TyFnPtr(fn_type) => {
ty::TyFnDef(_, _, fn_type) |
ty::TyFnPtr(fn_type) => {
let parameters = fn_type.skip_binder().inputs();
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty {
TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) |
TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => {
ty::TyRef(_, ty::TypeAndMut { mutbl: MutImmutable, .. }) |
ty::TyRawPtr(ty::TypeAndMut { mutbl: MutImmutable, .. }) => {
if let ExprAddrOf(MutMutable, _) = argument.node {
span_lint(cx,
UNNECESSARY_MUT_PASSED,
argument.span,
&format!("The function/method \"{}\" doesn't need a mutable reference", name));
&format!("The function/method `{}` doesn't need a mutable reference", name));
}
},
_ => (),

View file

@ -3,7 +3,7 @@
//! This lint is **warn** by default
use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext};
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::hir::Expr;
use syntax::ast;
use utils::{match_type, paths, span_lint};
@ -59,12 +59,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
let ty = cx.tables.expr_ty(expr);
if let ty::TyAdt(_, subst) = ty.sty {
if match_type(cx, ty, &paths::MUTEX) {
let mutex_param = &subst.type_at(0).sty;
let mutex_param = subst.type_at(0);
if let Some(atomic_name) = get_atomic_name(mutex_param) {
let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \
behaviour and not the internal type, consider using Mutex<()>.",
atomic_name);
match *mutex_param {
match mutex_param.sty {
ty::TyUint(t) if t != ast::UintTy::Us => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
ty::TyInt(t) if t != ast::IntTy::Is => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
_ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
@ -75,8 +75,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
}
}
fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> {
match *ty {
fn get_atomic_name(ty: Ty) -> Option<(&'static str)> {
match ty.sty {
ty::TyBool => Some("AtomicBool"),
ty::TyUint(_) => Some("AtomicUsize"),
ty::TyInt(_) => Some("AtomicIsize"),

View file

@ -5,6 +5,7 @@
use rustc::lint::*;
use rustc::hir::{ExprAddrOf, Expr, MutImmutable, Pat, PatKind, BindingMode};
use rustc::ty;
use rustc::ty::adjustment::{Adjustment, Adjust};
use utils::{span_lint, in_macro};
/// **What it does:** Checks for address of operations (`&`) that are going to
@ -41,9 +42,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
}
if let ExprAddrOf(MutImmutable, ref inner) = e.node {
if let ty::TyRef(..) = cx.tables.expr_ty(inner).sty {
if let Some(&ty::adjustment::Adjust::DerefRef { autoderefs, autoref, .. }) =
cx.tables.adjustments.get(&e.id).map(|a| &a.kind) {
if autoderefs > 1 && autoref.is_some() {
for adj3 in cx.tables.expr_adjustments(e).windows(3) {
if let [
Adjustment { kind: Adjust::Deref(_), .. },
Adjustment { kind: Adjust::Deref(_), .. },
Adjustment { kind: Adjust::Borrow(_), .. }
] = *adj3 {
span_lint(cx,
NEEDLESS_BORROW,
e.span,

View file

@ -82,8 +82,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let fn_def_id = cx.tcx.hir.local_def_id(node_id);
let preds: Vec<ty::Predicate> = {
let parameter_env = cx.tcx.param_env(fn_def_id);
traits::elaborate_predicates(cx.tcx, parameter_env.caller_bounds.to_vec())
traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
.filter(|p| !p.is_global())
.collect()
};
@ -91,12 +90,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Collect moved variables and spans which will need dereferencings from the function body.
let MovedVariablesCtxt { moved_vars, spans_need_deref, .. } = {
let mut ctx = MovedVariablesCtxt::new(cx);
let infcx = cx.tcx.borrowck_fake_infer_ctxt(body.id());
let region_maps = &cx.tcx.region_maps(fn_def_id);
{
let mut v = euv::ExprUseVisitor::new(&mut ctx, region_maps, &infcx);
v.consume_body(body);
}
euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_maps, cx.tables).consume_body(body);
ctx
};
@ -119,9 +114,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
if_let_chain! {[
!is_self(arg),
!ty.is_mutable_pointer(),
!is_copy(cx, ty, fn_def_id),
!implements_trait(cx, ty, fn_trait, &[], Some(node_id)),
!implements_trait(cx, ty, asref_trait, &[], Some(node_id)),
!is_copy(cx, ty),
!implements_trait(cx, ty, fn_trait, &[]),
!implements_trait(cx, ty, asref_trait, &[]),
!implements_borrow_trait,
let PatKind::Binding(mode, defid, ..) = arg.pat.node,
@ -190,7 +185,7 @@ struct MovedVariablesCtxt<'a, 'tcx: 'a> {
spans_need_deref: HashMap<DefId, HashSet<Span>>,
}
impl<'a, 'tcx: 'a> MovedVariablesCtxt<'a, 'tcx> {
impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
MovedVariablesCtxt {
cx: cx,
@ -262,7 +257,7 @@ impl<'a, 'tcx: 'a> MovedVariablesCtxt<'a, 'tcx> {
}
}
impl<'a, 'tcx: 'a> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
if let euv::ConsumeMode::Move(_) = mode {
self.move_common(consume_id, consume_span, cmt);

View file

@ -1,5 +1,5 @@
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty::TyAdt;
use rustc::ty;
use rustc::hir::{Expr, ExprStruct};
use utils::span_lint;
@ -34,7 +34,7 @@ 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.tables.expr_ty(expr);
if let TyAdt(def, _) = ty.sty {
if let ty::TyAdt(def, _) = ty.sty {
if fields.len() == def.struct_variant().fields.len() {
span_lint(cx,
NEEDLESS_UPDATE,

View file

@ -2,7 +2,7 @@ use rustc::hir::intravisit::FnKind;
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::lint::*;
use rustc::ty;
use rustc::ty::{self, Ty};
use syntax::ast;
use syntax::codemap::Span;
use utils::paths;
@ -108,15 +108,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
// can't be implemented by default
return;
}
let def_id = cx.tcx.hir.local_def_id(id);
if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
let self_ty = cx.tcx
.type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)));
if_let_chain!{[
self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics
same_tys(cx, self_ty, return_ty(cx, id), def_id),
same_tys(cx, self_ty, return_ty(cx, id)),
let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT),
!implements_trait(cx, self_ty, default_trait_id, &[], None)
!implements_trait(cx, self_ty, default_trait_id, &[])
], {
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
span_lint_and_then(cx,
@ -152,16 +150,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
}
}
fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
match ty.sty {
ty::TyAdt(adt_def, substs) if adt_def.is_struct() => {
for field in adt_def.all_fields() {
let f_ty = field.ty(cx.tcx, substs);
if !implements_trait(cx, f_ty, default_trait_id, &[], None) {
if !implements_trait(cx, f_ty, default_trait_id, &[]) {
return None;
}
}
cx.tcx.hir.span_if_local(adt_def.did)
Some(cx.tcx.def_span(adt_def.did))
},
_ => None,
}

View file

@ -49,10 +49,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ShouldAssertEq {
let ty1 = cx.tables.expr_ty(expr1);
let ty2 = cx.tables.expr_ty(expr2);
let parent = cx.tcx.hir.get_parent(e.id);
if implements_trait(cx, ty1, debug_trait, &[], Some(parent)) &&
implements_trait(cx, ty2, debug_trait, &[], Some(parent)) {
if implements_trait(cx, ty1, debug_trait, &[]) &&
implements_trait(cx, ty2, debug_trait, &[]) {
span_lint(cx, SHOULD_ASSERT_EQ, e.span, &format!("use `{}{}` for better reporting", debug, sugg));
}
}}

View file

@ -1,6 +1,5 @@
use rustc::lint::*;
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::hir::*;
use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet, last_path_segment};
use utils::sugg;
@ -101,7 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
e.span,
&format!("transmute from a type (`{}`) to itself", from_ty))
},
(&TyRef(_, rty), &TyRawPtr(ptr_ty)) => {
(&ty::TyRef(_, rty), &ty::TyRawPtr(ptr_ty)) => {
span_lint_and_then(cx,
USELESS_TRANSMUTE,
e.span,
@ -116,8 +115,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
db.span_suggestion(e.span, "try", sugg.to_string());
})
},
(&ty::TyInt(_), &TyRawPtr(_)) |
(&ty::TyUint(_), &TyRawPtr(_)) => {
(&ty::TyInt(_), &ty::TyRawPtr(_)) |
(&ty::TyUint(_), &ty::TyRawPtr(_)) => {
span_lint_and_then(cx,
USELESS_TRANSMUTE,
e.span,
@ -128,16 +127,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
arg.as_ty(&to_ty.to_string()).to_string());
})
},
(&ty::TyFloat(_), &TyRef(..)) |
(&ty::TyFloat(_), &TyRawPtr(_)) |
(&ty::TyChar, &TyRef(..)) |
(&ty::TyChar, &TyRawPtr(_)) => {
(&ty::TyFloat(_), &ty::TyRef(..)) |
(&ty::TyFloat(_), &ty::TyRawPtr(_)) |
(&ty::TyChar, &ty::TyRef(..)) |
(&ty::TyChar, &ty::TyRawPtr(_)) => {
span_lint(cx,
WRONG_TRANSMUTE,
e.span,
&format!("transmute from a `{}` to a pointer", from_ty))
},
(&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => {
(&ty::TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => {
span_lint(cx,
CROSSPOINTER_TRANSMUTE,
e.span,
@ -145,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
from_ty,
to_ty))
},
(_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => {
(_, &ty::TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => {
span_lint(cx,
CROSSPOINTER_TRANSMUTE,
e.span,
@ -153,7 +152,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
from_ty,
to_ty))
},
(&TyRawPtr(from_pty), &TyRef(_, to_rty)) => {
(&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_rty)) => {
span_lint_and_then(cx,
TRANSMUTE_PTR_TO_REF,
e.span,
@ -189,7 +188,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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: &QPath, to_rty: ty::Ty) -> String {
fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: Ty) -> String {
let seg = last_path_segment(path);
if_let_chain!{[
let PathParameters::AngleBracketedParameters(ref ang) = seg.parameters,

View file

@ -1,8 +1,9 @@
use reexport::*;
use rustc::hir;
use rustc::hir::*;
use rustc::hir::intravisit::{FnKind, Visitor, walk_ty, NestedVisitorMap};
use rustc::lint::*;
use rustc::ty;
use rustc::ty::{self, Ty};
use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::attr::IntType;
@ -106,7 +107,7 @@ fn check_fn_decl(cx: &LateContext, decl: &FnDecl) {
}
}
fn check_ty(cx: &LateContext, ast_ty: &Ty) {
fn check_ty(cx: &LateContext, ast_ty: &hir::Ty) {
if in_macro(ast_ty.span) {
return;
}
@ -196,8 +197,7 @@ declare_lint! {
fn check_let_unit(cx: &LateContext, decl: &Decl) {
if let DeclLocal(ref local) = decl.node {
let bindtype = &cx.tables.pat_ty(&local.pat).sty;
match *bindtype {
match cx.tables.pat_ty(&local.pat).sty {
ty::TyTuple(slice, _) if slice.is_empty() => {
if in_external_macro(cx, decl.span) || in_macro(local.pat.span) {
return;
@ -267,8 +267,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
if let ExprBinary(ref cmp, ref left, _) = expr.node {
let op = cmp.node;
if op.is_comparison() {
let sty = &cx.tables.expr_ty(left).sty;
match *sty {
match cx.tables.expr_ty(left).sty {
ty::TyTuple(slice, _) if slice.is_empty() => {
let result = match op {
BiEq | BiLe | BiGe => "true",
@ -398,7 +397,7 @@ declare_lint! {
/// Returns the size in bits of an integral type.
/// Will return 0 if the type is not an int or uint variant
fn int_ty_to_nbits(typ: &ty::TyS) -> usize {
fn int_ty_to_nbits(typ: Ty) -> usize {
let n = match typ.sty {
ty::TyInt(i) => 4 << (i as usize),
ty::TyUint(u) => 4 << (u as usize),
@ -412,7 +411,7 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize {
}
}
fn is_isize_or_usize(typ: &ty::TyS) -> bool {
fn is_isize_or_usize(typ: Ty) -> bool {
match typ.sty {
ty::TyInt(IntTy::Is) |
ty::TyUint(UintTy::Us) => true,
@ -420,7 +419,7 @@ fn is_isize_or_usize(typ: &ty::TyS) -> bool {
}
}
fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: bool) {
fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_to_f64: bool) {
let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
let arch_dependent_str = "on targets with 64-bit wide pointers ";
@ -453,7 +452,7 @@ enum ArchSuffix {
None,
}
fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) {
fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_to: Ty) {
let arch_64_suffix = " on targets with 64-bit wide pointers";
let arch_32_suffix = " on targets with 32-bit wide pointers";
let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
@ -693,7 +692,7 @@ impl<'a, 'tcx> TypeComplexityPass {
}
}
fn check_type(&self, cx: &LateContext, ty: &Ty) {
fn check_type(&self, cx: &LateContext, ty: &hir::Ty) {
if in_macro(ty.span) {
return;
}
@ -724,7 +723,7 @@ struct TypeComplexityVisitor {
}
impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
fn visit_ty(&mut self, ty: &'tcx Ty) {
fn visit_ty(&mut self, ty: &'tcx hir::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),
@ -909,9 +908,9 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
use rustc_const_eval::*;
use types::ExtremeType::*;
let ty = &cx.tables.expr_ty(expr).sty;
let ty = cx.tables.expr_ty(expr);
match *ty {
match ty.sty {
ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (),
_ => return None,
};
@ -921,7 +920,7 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
Err(_) => return None,
};
let which = match (ty, cv) {
let which = match (&ty.sty, cv) {
(&ty::TyBool, Bool(false)) |
(&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) |
(&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) |
@ -1070,7 +1069,6 @@ impl Ord for FullInt {
fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
use rustc::ty::TypeVariants::{TyInt, TyUint};
use syntax::ast::{IntTy, UintTy};
use std::*;
@ -1082,7 +1080,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
return None;
}
match pre_cast_ty.sty {
TyInt(int_ty) => {
ty::TyInt(int_ty) => {
Some(match int_ty {
IntTy::I8 => (FullInt::S(i8::min_value() as i128), FullInt::S(i8::max_value() as i128)),
IntTy::I16 => (FullInt::S(i16::min_value() as i128), FullInt::S(i16::max_value() as i128)),
@ -1092,7 +1090,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
IntTy::Is => (FullInt::S(isize::min_value() as i128), FullInt::S(isize::max_value() as i128)),
})
},
TyUint(uint_ty) => {
ty::TyUint(uint_ty) => {
Some(match uint_ty {
UintTy::U8 => (FullInt::U(u8::min_value() as u128), FullInt::U(u8::max_value() as u128)),
UintTy::U16 => (FullInt::U(u16::min_value() as u128), FullInt::U(u16::max_value() as u128)),
@ -1109,6 +1107,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
}
}
#[allow(cast_possible_wrap)]
fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
use rustc::middle::const_val::ConstVal::*;
use rustc_const_eval::ConstContext;
@ -1117,7 +1116,7 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
Ok(val) => {
if let Integral(const_int) = val {
match const_int.int_type() {
IntType::SignedInt(_) => #[allow(cast_possible_wrap)] Some(FullInt::S(const_int.to_u128_unchecked() as i128)),
IntType::SignedInt(_) => Some(FullInt::S(const_int.to_u128_unchecked() as i128)),
IntType::UnsignedInt(_) => Some(FullInt::U(const_int.to_u128_unchecked())),
}
} else {

View file

@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount {
hir::ExprMatch(ref res, _, _) if is_try(expr).is_some() => {
if let hir::ExprCall(ref func, ref args) = res.node {
if let hir::ExprPath(ref path) = func.node {
if match_path(path, &paths::CARRIER_TRANSLATE) && args.len() == 1 {
if match_path(path, &paths::TRY_INTO_RESULT) && args.len() == 1 {
check_method_call(cx, &args[0], expr);
}
}

View file

@ -76,8 +76,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
end: None,
limits: ast::RangeLimits::HalfOpen,
})
} else if match_path(path, &paths::RANGE_INCLUSIVE_STD) ||
match_path(path, &paths::RANGE_INCLUSIVE) {
} else if match_path(path, &paths::RANGE_INCLUSIVE_STD) || match_path(path, &paths::RANGE_INCLUSIVE) {
Some(Range {
start: get_field("start", fields),
end: get_field("end", fields),
@ -125,20 +124,17 @@ pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
pub fn for_loop(expr: &hir::Expr) -> Option<(&hir::Pat, &hir::Expr, &hir::Expr)> {
if_let_chain! {[
let hir::ExprMatch(ref iterexpr, ref arms, _) = expr.node,
let hir::ExprMatch(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.node,
let hir::ExprCall(_, ref iterargs) = iterexpr.node,
iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
let hir::ExprLoop(ref block, _, _) = arms[0].body.node,
block.stmts.is_empty(),
let Some(ref loopexpr) = block.expr,
let hir::ExprMatch(_, ref innerarms, hir::MatchSource::ForLoopDesugar) = loopexpr.node,
innerarms.len() == 2 && innerarms[0].pats.len() == 1,
let hir::PatKind::TupleStruct(_, ref somepats, _) = innerarms[0].pats[0].node,
somepats.len() == 1
block.expr.is_none(),
let [ ref let_stmt, ref body ] = *block.stmts,
let hir::StmtDecl(ref decl, _) = let_stmt.node,
let hir::DeclLocal(ref decl) = decl.node,
let hir::StmtExpr(ref expr, _) = body.node,
], {
return Some((&somepats[0],
&iterargs[0],
&innerarms[0].body));
return Some((&*decl.pat, &iterargs[0], expr));
}}
None
}

View file

@ -1,15 +1,13 @@
use reexport::*;
use rustc::hir;
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;
use rustc::traits::Reveal;
use rustc::traits;
use rustc::ty::subst::{Subst, Substs};
use rustc::ty;
use rustc::ty::layout::TargetDataLayout;
use rustc::ty::{self, TyCtxt, Ty};
use rustc::mir::transform::MirSource;
use rustc_errors;
use std::borrow::Cow;
@ -26,12 +24,12 @@ use syntax::symbol::keywords;
pub mod comparisons;
pub mod conf;
pub mod constants;
mod hir;
mod hir_utils;
pub mod paths;
pub mod sugg;
pub mod inspector;
pub mod internal_lints;
pub use self::hir::{SpanlessEq, SpanlessHash};
pub use self::hir_utils::{SpanlessEq, SpanlessHash};
pub type MethodArgs = HirVec<P<Expr>>;
@ -149,7 +147,7 @@ pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
/// ```
///
/// See also the `paths` module.
pub fn match_def_path(tcx: ty::TyCtxt, def_id: DefId, path: &[&str]) -> bool {
pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool {
use syntax::symbol;
struct AbsolutePathBuffer {
@ -175,7 +173,7 @@ pub fn match_def_path(tcx: ty::TyCtxt, def_id: DefId, path: &[&str]) -> bool {
}
/// Check if type is struct, enum or union type with given def path.
pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool {
pub fn match_type(cx: &LateContext, ty: Ty, path: &[&str]) -> bool {
match ty.sty {
ty::TyAdt(adt, _) => match_def_path(cx.tcx, adt.did, path),
_ => false,
@ -184,12 +182,8 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool {
/// Check if the method call given in `expr` belongs to given type.
pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
let method_call = ty::MethodCall::expr(expr.id);
let trt_id = cx.tables
.method_map
.get(&method_call)
.and_then(|callee| cx.tcx.impl_of_method(callee.def_id));
let method_call = cx.tables.type_dependent_defs[&expr.id];
let trt_id = cx.tcx.impl_of_method(method_call.def_id());
if let Some(trt_id) = trt_id {
match_def_path(cx.tcx, trt_id, path)
} else {
@ -199,12 +193,8 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
/// Check if the method call given in `expr` belongs to given trait.
pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
let method_call = ty::MethodCall::expr(expr.id);
let trt_id = cx.tables
.method_map
.get(&method_call)
.and_then(|callee| cx.tcx.trait_of_item(callee.def_id));
let method_call = cx.tables.type_dependent_defs[&expr.id];
let trt_id = cx.tcx.trait_of_item(method_call.def_id());
if let Some(trt_id) = trt_id {
match_def_path(cx.tcx, trt_id, path)
} else {
@ -267,7 +257,6 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
}
/// Get the definition associated to a path.
/// TODO: investigate if there is something more efficient for that.
pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
let cstore = &cx.tcx.sess.cstore;
@ -278,7 +267,7 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
krate: *krate,
index: CRATE_DEF_INDEX,
};
let mut items = cstore.item_children(krate);
let mut items = cstore.item_children(krate, cx.tcx.sess);
let mut path_it = path.iter().skip(1).peekable();
loop {
@ -293,7 +282,7 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
return Some(item.def);
}
items = cstore.item_children(item.def.def_id());
items = cstore.item_children(item.def.def_id(), cx.tcx.sess);
break;
}
}
@ -320,22 +309,16 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> {
/// See also `get_trait_def_id`.
pub fn implements_trait<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
ty: ty::Ty<'tcx>,
ty: Ty<'tcx>,
trait_id: DefId,
ty_params: &[ty::Ty<'tcx>],
parent_node_id: Option<NodeId>
ty_params: &[Ty<'tcx>]
) -> bool {
let ty = cx.tcx.erase_regions(&ty);
let mut b = if let Some(id) = parent_node_id {
cx.tcx.infer_ctxt(BodyId { node_id: id }, Reveal::All)
} else {
cx.tcx.infer_ctxt((), Reveal::All)
};
b.enter(|infcx| {
let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params);
traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
})
let obligation = cx.tcx
.predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params);
cx.tcx
.infer_ctxt()
.enter(|infcx| traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation))
}
/// Resolve the definition of a node from its `NodeId`.
@ -592,14 +575,21 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
/// replacement. In human-readable format though, it only appears once before the whole suggestion.
pub fn multispan_sugg(db: &mut DiagnosticBuilder, help_msg: String, sugg: Vec<(Span, String)>) {
let sugg = rustc_errors::CodeSuggestion {
substitution_parts: sugg.into_iter().map(|(span, sub)| rustc_errors::Substitution { span, substitutions: vec![sub] }).collect(),
substitution_parts: sugg.into_iter()
.map(|(span, sub)| {
rustc_errors::Substitution {
span: span,
substitutions: vec![sub],
}
})
.collect(),
msg: help_msg,
};
db.suggestions.push(sugg);
}
/// Return the base type for references and raw pointers.
pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty {
pub fn walk_ptrs_ty(ty: Ty) -> Ty {
match ty.sty {
ty::TyRef(_, ref tm) => walk_ptrs_ty(tm.ty),
_ => ty,
@ -607,8 +597,8 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty {
}
/// Return the base type for references and raw pointers, and count reference depth.
pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) {
fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) {
pub fn walk_ptrs_ty_depth(ty: Ty) -> (Ty, usize) {
fn inner(ty: Ty, depth: usize) -> (Ty, usize) {
match ty.sty {
ty::TyRef(_, ref tm) => inner(tm.ty, depth + 1),
_ => (ty, depth),
@ -772,7 +762,7 @@ pub fn camel_case_from(s: &str) -> usize {
}
/// Convenience function to get the return type of a function
pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::Ty<'tcx> {
pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Ty<'tcx> {
let fn_def_id = cx.tcx.hir.local_def_id(fn_item);
let ret_ty = cx.tcx.type_of(fn_def_id).fn_sig().output();
cx.tcx.erase_late_bound_regions(&ret_ty)
@ -781,23 +771,12 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T
/// Check if two types are the same.
// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but
// not for type parameters.
pub fn same_tys<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
a: ty::Ty<'tcx>,
b: ty::Ty<'tcx>,
parameter_item: DefId
) -> bool {
let parameter_env = cx.tcx.param_env(parameter_item);
cx.tcx.infer_ctxt(parameter_env, Reveal::All).enter(|infcx| {
let substs = Substs::identity_for_item(cx.tcx, parameter_item);
let new_a = a.subst(infcx.tcx, substs);
let new_b = b.subst(infcx.tcx, substs);
infcx.can_equate(&new_a, &new_b).is_ok()
})
pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
cx.tcx.infer_ctxt().enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok())
}
/// Return whether the given type is an `unsafe` function.
pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
pub fn type_is_unsafe_function(ty: Ty) -> bool {
match ty.sty {
ty::TyFnDef(_, _, f) |
ty::TyFnPtr(f) => f.unsafety() == Unsafety::Unsafe,
@ -805,10 +784,8 @@ pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
}
}
pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, env: DefId) -> bool {
let substs = Substs::identity_for_item(cx.tcx, env);
let env = cx.tcx.param_env(env);
!ty.subst(cx.tcx, substs).moves_by_default(cx.tcx.global_tcx(), env, DUMMY_SP)
pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
!ty.moves_by_default(cx.tcx.global_tcx(), cx.param_env, DUMMY_SP)
}
/// Return whether a pattern is refutable.
@ -910,7 +887,7 @@ pub fn is_self(slf: &Arg) -> bool {
}
}
pub fn is_self_ty(slf: &Ty) -> bool {
pub fn is_self_ty(slf: &hir::Ty) -> bool {
if_let_chain! {[
let TyPath(ref qp) = slf.node,
let QPath::Resolved(None, ref path) = *qp,
@ -969,8 +946,6 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> {
None
}
pub fn type_size<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>) -> Option<u64> {
cx.tcx
.infer_ctxt((), Reveal::All)
.enter(|infcx| ty.layout(&infcx).ok().map(|lay| lay.size(&TargetDataLayout::parse(cx.sess())).bytes()))
pub fn type_size<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<u64> {
ty.layout(cx.tcx, cx.param_env).ok().map(|layout| layout.size(cx.tcx).bytes())
}

View file

@ -1,5 +1,6 @@
//! This module contains paths to types and functions Clippy needs to know about.
pub const ASMUT_TRAIT: [&'static str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&'static str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&'static str; 3] = ["std", "panicking", "begin_panic"];
pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"];
@ -9,7 +10,6 @@ pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"];
pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"];
pub const CARRIER_TRANSLATE: [&'static str; 4] = ["std", "ops", "Carrier", "translate"];
pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"];
pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"];
@ -72,6 +72,7 @@ pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
pub const TO_OWNED: [&'static str; 3] = ["collections", "borrow", "ToOwned"];
pub const TO_STRING: [&'static str; 3] = ["collections", "string", "ToString"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_INTO_RESULT: [&'static str; 4] = ["std", "ops", "Try", "into_result"];
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&'static str; 3] = ["collections", "vec", "from_elem"];

View file

@ -1,6 +1,6 @@
use rustc::hir::*;
use rustc::lint::*;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc_const_eval::ConstContext;
use syntax::codemap::Span;
use utils::{higher, is_copy, snippet, span_lint_and_then};
@ -35,8 +35,8 @@ 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.tables.expr_ty_adjusted(expr).sty,
let ty::TypeVariants::TySlice(..) = ty.ty.sty,
let ty::TyRef(_, ref ty) = cx.tables.expr_ty_adjusted(expr).sty,
let ty::TySlice(..) = ty.ty.sty,
let ExprAddrOf(_, ref addressee) = expr.node,
let Some(vec_args) = higher::vec_macro(cx, addressee),
], {
@ -47,7 +47,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if_let_chain!{[
let Some((_, arg, _)) = higher::for_loop(expr),
let Some(vec_args) = higher::vec_macro(cx, arg),
is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)), cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(expr.id))),
is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg))),
], {
// report the error around the `vec!` not inside `<std macros>:`
let span = arg.span.ctxt.outer().expn_info().map(|info| info.call_site).expect("unable to get call_site");
@ -88,7 +88,7 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
}
/// Return the item type of the vector (ie. the `T` in `Vec<T>`).
fn vec_type(ty: ty::Ty) -> ty::Ty {
fn vec_type(ty: Ty) -> Ty {
if let ty::TyAdt(_, substs) = ty.sty {
substs.type_at(0)
} else {

View file

@ -166,6 +166,14 @@ error: manual implementation of an assign operation
|
= note: `-D assign-op-pattern` implied by `-D warnings`
error: manual implementation of an assign operation
--> assign_ops.rs:40:5
|
40 | s = s + "bla";
| ^^^^^^^^^^^^^ help: replace it with `s += "bla"`
|
= note: `-D assign-op-pattern` implied by `-D warnings`
error: aborting due to previous error(s)
error: Could not compile `clippy_tests`.

View file

@ -317,6 +317,14 @@ error: this range is empty so this for loop will never run
|
= note: `-D reverse-range-loop` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> for_loop.rs:192:22
|
192 | for i in (10..8).step_by(-1) {
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
--> for_loop.rs:207:15
|

View file

@ -1,4 +1,4 @@
error: The function/method "takes_an_immutable_reference" doesn't need a mutable reference
error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
--> mut_reference.rs:22:34
|
22 | takes_an_immutable_reference(&mut 42);
@ -6,7 +6,7 @@ error: The function/method "takes_an_immutable_reference" doesn't need a mutable
|
= note: `-D unnecessary-mut-passed` implied by `-D warnings`
error: The function/method "as_ptr" doesn't need a mutable reference
error: The function/method `as_ptr` doesn't need a mutable reference
--> mut_reference.rs:24:12
|
24 | as_ptr(&mut 42);
@ -14,7 +14,7 @@ error: The function/method "as_ptr" doesn't need a mutable reference
|
= note: `-D unnecessary-mut-passed` implied by `-D warnings`
error: The function/method "takes_an_immutable_reference" doesn't need a mutable reference
error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
--> mut_reference.rs:28:44
|
28 | my_struct.takes_an_immutable_reference(&mut 42);

View file

@ -6,6 +6,22 @@ error: Range::step_by(0) produces an infinite iterator. Consider using `std::ite
|
= note: `-D range-step-by-zero` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> range.rs:13:12
|
13 | (0..1).step_by(0);
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> range.rs:15:12
|
15 | (0..1).step_by(1);
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` instead
--> range.rs:17:5
|
@ -14,6 +30,14 @@ error: Range::step_by(0) produces an infinite iterator. Consider using `std::ite
|
= note: `-D range-step-by-zero` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> range.rs:17:11
|
17 | (1..).step_by(0);
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` instead
--> range.rs:18:5
|
@ -22,6 +46,14 @@ error: Range::step_by(0) produces an infinite iterator. Consider using `std::ite
|
= note: `-D range-step-by-zero` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> range.rs:18:13
|
18 | (1...2).step_by(0);
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` instead
--> range.rs:21:5
|
@ -30,6 +62,14 @@ error: Range::step_by(0) produces an infinite iterator. Consider using `std::ite
|
= note: `-D range-step-by-zero` implied by `-D warnings`
error: use of deprecated item: replaced by `Iterator::step_by`
--> range.rs:21:7
|
21 | x.step_by(0);
| ^^^^^^^
|
= note: `-D deprecated` implied by `-D warnings`
error: It is more idiomatic to use v1.iter().enumerate()
--> range.rs:29:14
|

View file

@ -1,3 +1,11 @@
error: manual implementation of an assign operation
--> strings.rs:10:9
|
10 | x = x + ".";
| ^^^^^^^^^^^ help: replace it with `x += "."`
|
= note: `-D assign-op-pattern` implied by `-D warnings`
error: you added something to a string. Consider using `String::push_str()` instead
--> strings.rs:10:13
|
@ -22,6 +30,14 @@ error: you assigned the result of adding something to this string. Consider usin
|
= note: `-D string-add-assign` implied by `-D warnings`
error: manual implementation of an assign operation
--> strings.rs:24:9
|
24 | x = x + ".";
| ^^^^^^^^^^^ help: replace it with `x += "."`
|
= note: `-D assign-op-pattern` implied by `-D warnings`
error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead
--> strings.rs:38:9
|
@ -30,6 +46,14 @@ error: you assigned the result of adding something to this string. Consider usin
|
= note: `-D string-add-assign` implied by `-D warnings`
error: manual implementation of an assign operation
--> strings.rs:38:9
|
38 | x = x + ".";
| ^^^^^^^^^^^ help: replace it with `x += "."`
|
= note: `-D assign-op-pattern` implied by `-D warnings`
error: you added something to a string. Consider using `String::push_str()` instead
--> strings.rs:42:13
|

View file

@ -29,6 +29,8 @@ impl Foo {
#[allow(wrong_self_convention)]
pub fn from_cake(self) {}
fn as_x<F: AsRef<Self>>(_: F) { }
fn as_y<F: AsRef<Foo>>(_: F) { }
}
struct Bar;

View file

@ -15,81 +15,81 @@ error: methods called `from_*` usually take no self; consider choosing a less am
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
--> wrong_self_convention.rs:38:15
--> wrong_self_convention.rs:40:15
|
38 | fn as_i32(self) {}
40 | fn as_i32(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
--> wrong_self_convention.rs:40:17
--> wrong_self_convention.rs:42:17
|
40 | fn into_i32(&self) {}
42 | fn into_i32(&self) {}
| ^^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
--> wrong_self_convention.rs:42:15
--> wrong_self_convention.rs:44:15
|
42 | fn is_i32(self) {}
44 | fn is_i32(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
--> wrong_self_convention.rs:44:15
--> wrong_self_convention.rs:46:15
|
44 | fn to_i32(self) {}
46 | fn to_i32(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
--> wrong_self_convention.rs:46:17
--> wrong_self_convention.rs:48:17
|
46 | fn from_i32(self) {}
48 | fn from_i32(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
--> wrong_self_convention.rs:48:19
--> wrong_self_convention.rs:50:19
|
48 | pub fn as_i64(self) {}
50 | pub fn as_i64(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
--> wrong_self_convention.rs:49:21
--> wrong_self_convention.rs:51:21
|
49 | pub fn into_i64(&self) {}
51 | pub fn into_i64(&self) {}
| ^^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
--> wrong_self_convention.rs:50:19
--> wrong_self_convention.rs:52:19
|
50 | pub fn is_i64(self) {}
52 | pub fn is_i64(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
--> wrong_self_convention.rs:51:19
--> wrong_self_convention.rs:53:19
|
51 | pub fn to_i64(self) {}
53 | pub fn to_i64(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`
error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
--> wrong_self_convention.rs:52:21
--> wrong_self_convention.rs:54:21
|
52 | pub fn from_i64(self) {}
54 | pub fn from_i64(self) {}
| ^^^^
|
= note: `-D wrong-self-convention` implied by `-D warnings`