# Change Log
All notable changes to this project will be documented in this file.
+## 0.0.113 — 2017-02-04
+* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
+* New lint: [`large_enum_variant`]
+* `explicit_into_iter_loop` provides suggestions
+
## 0.0.112 — 2017-01-27
* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
[`double_parens`]: https://github.com/Manishearth/rust-clippy/wiki#double_parens
[`drop_ref`]: https://github.com/Manishearth/rust-clippy/wiki#drop_ref
[`duplicate_underscore_argument`]: https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument
+[`empty_enum`]: https://github.com/Manishearth/rust-clippy/wiki#empty_enum
[`empty_loop`]: https://github.com/Manishearth/rust-clippy/wiki#empty_loop
[`enum_clike_unportable_variant`]: https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant
[`enum_glob_use`]: https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use
[package]
name = "clippy"
-version = "0.0.112"
+version = "0.0.113"
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",
"Andre Bogus <bogusandre@gmail.com>",
[dependencies]
# begin automatic update
-clippy_lints = { version = "0.0.112", path = "clippy_lints" }
+clippy_lints = { version = "0.0.113", path = "clippy_lints" }
# end automatic update
cargo_metadata = "0.1.1"
[double_parens](https://github.com/Manishearth/rust-clippy/wiki#double_parens) | warn | Warn on unnecessary double parentheses
[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | calls to `std::mem::drop` with a reference instead of an owned value
[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | function arguments having names which only differ by an underscore
+[empty_enum](https://github.com/Manishearth/rust-clippy/wiki#empty_enum) | allow | enum with no variants
[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}`, which should block or sleep
[enum_clike_unportable_variant](https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant) | warn | C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`
[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | use items that import all variants of an enum
[package]
name = "clippy_lints"
# begin automatic update
-version = "0.0.112"
+version = "0.0.113"
# end automatic update
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",
return; // useless if the trait doesn't exist
};
// check that we are not inside an `impl AssignOp` of this exact operation
- let parent_fn = cx.tcx.map.get_parent(e.id);
- let parent_impl = cx.tcx.map.get_parent(parent_fn);
+ let parent_fn = cx.tcx.hir.get_parent(e.id);
+ let parent_impl = cx.tcx.hir.get_parent(parent_fn);
// the crate node is the only one that is not in the map
if_let_chain!{[
parent_impl != ast::CRATE_NODE_ID,
- let hir::map::Node::NodeItem(item) = cx.tcx.map.get(parent_impl),
+ let hir::map::Node::NodeItem(item) = cx.tcx.hir.get(parent_impl),
let hir::Item_::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node,
trait_ref.path.def.def_id() == trait_id
], { return; }}
fn is_relevant_item(tcx: ty::TyCtxt, item: &Item) -> bool {
if let ItemFn(_, _, _, _, _, eid) = item.node {
- is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.map.body(eid).value)
+ is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
} else {
false
}
fn is_relevant_impl(tcx: ty::TyCtxt, item: &ImplItem) -> bool {
match item.node {
- ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.map.body(eid).value),
+ ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value),
_ => false,
}
}
match item.node {
TraitItemKind::Method(_, TraitMethod::Required(_)) => true,
TraitItemKind::Method(_, TraitMethod::Provided(eid)) => {
- is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.map.body(eid).value)
+ is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
},
_ => false,
}
}
-fn is_relevant_block(tcx: ty::TyCtxt, tables: &ty::Tables, block: &Block) -> bool {
+fn is_relevant_block(tcx: ty::TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool {
for stmt in &block.stmts {
match stmt.node {
StmtDecl(_, _) => return true,
block.expr.as_ref().map_or(false, |e| is_relevant_expr(tcx, tables, e))
}
-fn is_relevant_expr(tcx: ty::TyCtxt, tables: &ty::Tables, expr: &Expr) -> bool {
+fn is_relevant_expr(tcx: ty::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),
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 body = self.cx.tcx.map.body(eid);
+ let body = self.cx.tcx.hir.body(eid);
let ex = &body.value;
if matches!(ex.node, ExprBlock(_)) {
self.found_block = Some(ex);
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
ExprRepeat(ref value, number_id) => {
if let Some(lcx) = self.lcx {
self.binop_apply(value,
- &lcx.tcx.map.body(number_id).value,
+ &lcx.tcx.hir.body(number_id).value,
|v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize)))
} else {
None
span: Span,
node_id: NodeId
) {
- let def_id = cx.tcx.map.local_def_id(node_id);
+ let def_id = cx.tcx.hir.local_def_id(node_id);
if !cx.tcx.has_attr(def_id, "test") {
self.check(cx, &body.value, span);
}
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 ty = cx.tcx.item_type(cx.tcx.hir.local_def_id(item.id));
let is_automatically_derived = is_automatically_derived(&*item.attrs);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
cx, DERIVE_HASH_XOR_EQ, span,
mess,
|db| {
- if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) {
+ if let Some(node_id) = cx.tcx.hir.as_local_node_id(impl_id) {
db.span_note(
- cx.tcx.map.span(node_id),
+ cx.tcx.hir.span(node_id),
"`PartialEq` implemented here"
);
}
--- /dev/null
+//! lint when there is an enum with no variants
+
+use rustc::lint::*;
+use rustc::hir::*;
+use utils::span_lint_and_then;
+
+/// **What it does:** Checks for `enum`s with no variants.
+///
+/// **Why is this bad?** Enum's with no variants should be replaced with `!`, the uninhabited type,
+/// or a wrapper around it.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// enum Test {}
+/// ```
+declare_lint! {
+ pub EMPTY_ENUM,
+ Allow,
+ "enum with no variants"
+}
+
+#[derive(Copy,Clone)]
+pub struct EmptyEnum;
+
+impl LintPass for EmptyEnum {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(EMPTY_ENUM)
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum {
+ fn check_item(&mut self, cx: &LateContext, item: &Item) {
+ let did = cx.tcx.hir.local_def_id(item.id);
+ if let ItemEnum(..) = item.node {
+ let ty = cx.tcx.item_type(did);
+ let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+ if adt.variants.is_empty() {
+ span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| {
+ db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it");
+ });
+ }
+ }
+ }
+}
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
if let Some(body_id) = variant.disr_expr {
use rustc_const_eval::*;
let constcx = ConstContext::new(cx.tcx, body_id);
- let bad = match constcx.eval(&cx.tcx.map.body(body_id).value, EvalHint::ExprTypeChecked) {
+ let bad = match constcx.eval(&cx.tcx.hir.body(body_id).value, EvalHint::ExprTypeChecked) {
Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i,
Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i,
_ => false,
}
fn is_non_trait_box(ty: ty::Ty) -> bool {
- match ty.sty {
- ty::TyBox(inner) => !inner.is_trait(),
- _ => false,
- }
+ ty.is_box() && !ty.boxed_ty().is_trait()
}
struct EscapeDelegate<'a, 'tcx: 'a> {
set: NodeSet,
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
- tables: &'a ty::Tables<'tcx>,
+ tables: &'a ty::TypeckTables<'tcx>,
target: TargetDataLayout,
too_large_for_stack: u64,
}
for node in v.set {
span_lint(cx,
BOXED_LOCAL,
- cx.tcx.map.span(node),
+ cx.tcx.hir.span(node),
"local variable doesn't need to be boxed here");
}
}
}
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.map;
+ let map = &self.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)) {
self.tables
.adjustments
.get(&self.tcx
- .map
+ .hir
.get_parent_node(borrow_id))
.map(|a| &a.kind) {
if autoderefs <= 1 {
fn is_large_box(&self, ty: ty::Ty<'tcx>) -> bool {
// Large types need to be boxed to avoid stack
// overflows.
- match ty.sty {
- ty::TyBox(inner) => {
- 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
- })
- },
- _ => false,
+ 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
+ })
+ } else {
+ false
}
}
}
fn check_closure(cx: &LateContext, expr: &Expr) {
if let ExprClosure(_, ref decl, eid, _) = expr.node {
- let body = cx.tcx.map.body(eid);
+ let body = cx.tcx.hir.body(eid);
let ex = &body.value;
if let ExprCall(ref caller, ref args) = ex.node {
if args.len() != decl.inputs.len() {
// 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)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor) {
- let map = &vis.cx.tcx.map;
+ let map = &vis.cx.tcx.hir;
let mut cur_id = vis.write_expr.id;
loop {
let parent_id = map.get_parent_node(cur_id);
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
block.stmts.len() == 1,
let StmtDecl(ref decl, _) = block.stmts[0].node,
let DeclItem(ref decl) = decl.node,
- let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id),
+ let Some(NodeItem(decl)) = cx.tcx.hir.find(decl.id),
&*decl.name.as_str() == "__STATIC_FMTSTR",
let ItemStatic(_, _, ref expr) = decl.node,
- let ExprAddrOf(_, ref expr) = cx.tcx.map.body(*expr).value.node, // &["…", "…", …]
+ let ExprAddrOf(_, ref expr) = cx.tcx.hir.body(*expr).value.node, // &["…", "…", …]
let ExprArray(ref exprs) = expr.node,
], {
let mut result = Vec::new();
) {
use rustc::hir::map::Node::*;
- let is_impl = if let Some(NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
+ let is_impl = if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(nodeid)) {
matches!(item.node, hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..))
} else {
false
}
if let hir::TraitMethod::Provided(eid) = *eid {
- let body = cx.tcx.map.body(eid);
+ let body = cx.tcx.hir.body(eid);
self.check_raw_ptr(cx, sig.unsafety, &sig.decl, body, item.id);
}
}
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)
+ intravisit::NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
- let did = cx.tcx.map.local_def_id(item.id);
+ let did = cx.tcx.hir.local_def_id(item.id);
if let ItemEnum(ref def, _) = item.node {
let ty = cx.tcx.item_type(did);
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if let AssociatedItemKind::Method { has_self } = item.kind {
has_self &&
{
- let did = cx.tcx.map.local_def_id(item.id.node_id);
+ let did = cx.tcx.hir.local_def_id(item.id.node_id);
let impl_ty = cx.tcx.item_type(did);
impl_ty.fn_args().skip_binder().len() == 1
}
if let AssociatedItemKind::Method { has_self } = item.kind {
has_self &&
{
- let did = cx.tcx.map.local_def_id(item.id.node_id);
+ let did = cx.tcx.hir.local_def_id(item.id.node_id);
let impl_ty = cx.tcx.item_type(did);
impl_ty.fn_args().skip_binder().len() == 1
}
if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
if cx.access_levels.is_exported(i.id.node_id) {
- let def_id = cx.tcx.map.local_def_id(item.id);
+ let def_id = cx.tcx.hir.local_def_id(item.id);
let ty = cx.tcx.item_type(def_id);
span_lint(cx,
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)
+ hir::intravisit::NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)]
-#![feature(repeat_str)]
#![feature(conservative_impl_trait)]
#![feature(collections_bound)]
pub mod doc;
pub mod double_parens;
pub mod drop_forget_ref;
+pub mod empty_enum;
pub mod entry;
pub mod enum_clike;
pub mod enum_glob_use;
max_single_char_names: conf.max_single_char_names,
});
reg.register_late_lint_pass(box drop_forget_ref::Pass);
+ reg.register_late_lint_pass(box empty_enum::EmptyEnum);
reg.register_late_lint_pass(box types::AbsurdExtremeComparisons);
reg.register_late_lint_pass(box types::InvalidUpcastComparisons);
reg.register_late_lint_pass(box regex::Pass::default());
reg.register_lint_group("clippy_pedantic", vec![
booleans::NONMINIMAL_BOOL,
+ empty_enum::EMPTY_ENUM,
enum_glob_use::ENUM_GLOB_USE,
enum_variants::PUB_ENUM_VARIANT_NAMES,
enum_variants::STUTTER,
if let Some(ref lt) = *lifetime {
if &*lt.name.as_str() == "'static" {
self.lts.push(RefLt::Static);
+ } else if lt.is_elided() {
+ self.lts.push(RefLt::Unnamed);
} else {
self.lts.push(RefLt::Named(lt.name));
}
fn visit_ty(&mut self, ty: &'tcx Ty) {
match ty.node {
- TyRptr(None, _) => {
+ TyRptr(ref lt, _) if lt.is_elided() => {
self.record(&None);
},
TyPath(ref path) => {
}
}
},
+ TyTraitObject(ref bounds, ref lt) => {
+ if !lt.is_elided() {
+ self.record(&Some(*lt));
+ }
+ for bound in bounds {
+ self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
+ }
+ return;
+ },
_ => (),
}
walk_ty(self, ty);
// For each candidate, check the parent block to see if
// it's initialized to zero at the start of the loop.
- let map = &cx.tcx.map;
+ let map = &cx.tcx.hir;
let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id));
if let Some(parent_id) = parent_scope {
if let NodeBlock(block) = map.get(parent_id) {
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
match def {
Def::Local(..) | Def::Upvar(..) => {
let def_id = def.def_id();
- let node_id = self.cx.tcx.map.as_local_node_id(def_id).unwrap();
+ let node_id = self.cx.tcx.hir.as_local_node_id(def_id).unwrap();
let extent = self.cx.tcx.region_maps.var_scope(node_id);
self.indexed.insert(seqvar.segments[0].name, Some(extent));
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
if let ExprPath(ref qpath) = expr.node {
let path_res = cx.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");
+ let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("That DefId should be valid");
return Some(node_id);
}
}
if &*name.node.as_str() == "map" && args.len() == 2 {
match args[1].node {
ExprClosure(_, ref decl, closure_eid, _) => {
- let body = cx.tcx.map.body(closure_eid);
+ let body = cx.tcx.hir.body(closure_eid);
let closure_expr = remove_blocks(&body.value);
if_let_chain! {[
// nothing special in the argument, besides reference bindings
return;
}
let name = implitem.name;
- let parent = cx.tcx.map.get_parent(implitem.id);
- let item = cx.tcx.map.expect_item(parent);
+ let parent = cx.tcx.hir.get_parent(implitem.id);
+ let item = cx.tcx.hir.expect_item(parent);
if_let_chain! {[
let hir::ImplItemKind::Method(ref sig, id) = implitem.node,
let Some(first_arg_ty) = sig.decl.inputs.get(0),
- let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.map.body(id)).next(),
+ let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir.body(id)).next(),
let hir::ItemImpl(_, _, _, None, ref self_ty, _) = item.node,
], {
// check missing trait implementations
}
// check conventions w.r.t. conversion method names and predicates
- let ty = cx.tcx.item_type(cx.tcx.map.local_def_id(item.id));
+ let ty = cx.tcx.item_type(cx.tcx.hir.local_def_id(item.id));
let is_copy = is_copy(cx, ty, item.id);
for &(ref conv, self_kinds) in &CONVENTIONS {
if_let_chain! {[
/// Checks for the `CLONE_ON_COPY` lint.
fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_ty: ty::Ty) {
let ty = cx.tables.expr_ty(expr);
- let parent = cx.tcx.map.get_parent(expr.id);
+ let parent = cx.tcx.hir.get_parent(expr.id);
let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent);
if let ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) = arg_ty.sty {
if let ty::TyRef(..) = inner.sty {
fn may_slice(cx: &LateContext, ty: ty::Ty) -> bool {
match ty.sty {
ty::TySlice(_) => true,
+ ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
ty::TyAdt(..) => match_type(cx, ty, &paths::VEC),
ty::TyArray(_, size) => size < 32,
- ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) |
- ty::TyBox(inner) => may_slice(cx, inner),
+ ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) => may_slice(cx, inner),
_ => false,
}
}
} else {
match ty.sty {
ty::TySlice(_) => sugg::Sugg::hir_opt(cx, expr),
- ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) |
- ty::TyBox(inner) => {
+ ty::TyAdt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
+ ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) => {
if may_slice(cx, inner) {
sugg::Sugg::hir_opt(cx, expr)
} else {
match *def {
def::Def::Local(id) |
def::Def::Upvar(id, _, _) => {
- if let Some(span) = cx.tcx.map.span_if_local(id) {
+ if let Some(span) = cx.tcx.hir.span_if_local(id) {
!in_macro(cx, span)
} else {
true
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);
+ let def_id = cx.tcx.hir.local_def_id(impl_item.id);
match cx.tcx.associated_item(def_id).container {
ty::TraitContainer(_) => return,
ty::ImplContainer(cid) => {
intravisit::walk_ty(self, ty);
}
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
- intravisit::NestedVisitorMap::All(&self.cx.tcx.map)
+ intravisit::NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
}
if decl.inputs.is_empty() && &*name.as_str() == "new" && cx.access_levels.is_reachable(id) {
let self_ty = cx.tcx
- .item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id)));
+ .item_type(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), id),
return None;
}
}
- cx.tcx.map.span_if_local(adt_def.did)
+ cx.tcx.hir.span_if_local(adt_def.did)
},
_ => None,
}
}
fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
- let map = &cx.tcx.map;
+ let map = &cx.tcx.hir;
// `fmt` method
if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
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 Some(NodeItem(it)) = cx.tcx.hir.find(cx.tcx.hir.get_parent(item.id)) {
if let ItemImpl(_, _, _, Some(_), _, _) = it.node {
return; // ignore trait impls
}
}
fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
- let fn_def_id = cx.tcx.map.local_def_id(fn_id);
+ let fn_def_id = cx.tcx.hir.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()) {
TySlice(ref sty) => check_ty(cx, sty, bindings),
TyArray(ref fty, body_id) => {
check_ty(cx, fty, bindings);
- check_expr(cx, &cx.tcx.map.body(body_id).value, bindings);
+ check_expr(cx, &cx.tcx.hir.body(body_id).value, bindings);
},
TyPtr(MutTy { ty: ref mty, .. }) |
TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings),
check_ty(cx, t, bindings)
}
},
- TyTypeof(body_id) => check_expr(cx, &cx.tcx.map.body(body_id).value, bindings),
+ TyTypeof(body_id) => check_expr(cx, &cx.tcx.hir.body(body_id).value, bindings),
_ => (),
}
}
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass {
fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Body, _: Span, id: NodeId) {
// skip trait implementations, see #605
- if let Some(map::NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent(id)) {
+ if let Some(map::NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent(id)) {
if let ItemImpl(_, _, _, Some(..), _, _) = item.node {
return;
}
// function types bring a lot of overhead
TyBareFn(..) => (50 * self.nest, 1),
- TyTraitObject(ref bounds) => {
- let has_lifetimes = bounds.iter()
- .any(|bound| match *bound {
- TraitTyParamBound(ref poly_trait, ..) => !poly_trait.bound_lifetimes.is_empty(),
- RegionTyParamBound(..) => true,
- });
- if has_lifetimes {
+ TyTraitObject(ref param_bounds, _) => {
+ let has_lifetime_parameters = param_bounds.iter()
+ .any(|bound| !bound.bound_lifetimes.is_empty());
+ if has_lifetime_parameters {
// complex trait bounds like A<'a, 'b>
(50 * self.nest, 1)
} else {
self.nest -= sub_nest;
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
},
(&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => {
self.eq_expr(le, re) &&
- self.eq_expr(&self.cx.tcx.map.body(ll_id).value, &self.cx.tcx.map.body(rl_id).value)
+ self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
},
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
(&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => {
self.eq_ty(lt, rt) &&
- self.eq_expr(&self.cx.tcx.map.body(ll_id).value, &self.cx.tcx.map.body(rl_id).value)
+ self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
},
(&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
let c: fn(_, _, _, _) -> _ = ExprClosure;
c.hash(&mut self.s);
cap.hash(&mut self.s);
- self.hash_expr(&self.cx.tcx.map.body(eid).value);
+ self.hash_expr(&self.cx.tcx.hir.body(eid).value);
},
ExprField(ref e, ref f) => {
let c: fn(_, _) -> _ = ExprField;
let c: fn(_, _) -> _ = ExprRepeat;
c.hash(&mut self.s);
self.hash_expr(e);
- self.hash_expr(&self.cx.tcx.map.body(l_id).value);
+ self.hash_expr(&self.cx.tcx.hir.body(l_id).value);
},
ExprRet(ref e) => {
let c: fn(_) -> _ = ExprRet;
match item.node {
hir::ImplItemKind::Const(_, body_id) => {
println!("associated constant");
- print_expr(cx, &cx.tcx.map.body(body_id).value, 1);
+ print_expr(cx, &cx.tcx.hir.body(body_id).value, 1);
},
hir::ImplItemKind::Method(..) => println!("method"),
hir::ImplItemKind::Type(_) => println!("associated type"),
println!("{}value:", ind);
print_expr(cx, val, indent + 1);
println!("{}repeat count:", ind);
- print_expr(cx, &cx.tcx.map.body(body_id).value, indent + 1);
+ print_expr(cx, &cx.tcx.hir.body(body_id).value, indent + 1);
},
}
}
fn print_item(cx: &LateContext, item: &hir::Item) {
- let did = cx.tcx.map.local_def_id(item.id);
+ let did = cx.tcx.hir.local_def_id(item.id);
println!("item `{}`", item.name);
match item.vis {
hir::Visibility::Public => println!("public"),
output: &mut self.registered_lints,
cx: cx,
};
- collector.visit_expr(&cx.tcx.map.body(body_id).value);
+ collector.visit_expr(&cx.tcx.hir.body(body_id).value);
}
}
}
fn is_lint_ref_type(ty: &Ty) -> bool {
- if let TyRptr(Some(_), MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node {
+ if let TyRptr(ref lt, MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node {
+ if lt.is_elided() {
+ return false;
+ }
if let TyPath(ref path) = inner.node {
return match_path(path, &paths::LINT);
}
}
}
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::All(&self.cx.tcx.map)
+ NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
/// Get the name of the item the expression is in, if available.
pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
- let parent_id = cx.tcx.map.get_parent(expr.id);
- match cx.tcx.map.find(parent_id) {
+ let parent_id = cx.tcx.hir.get_parent(expr.id);
+ match cx.tcx.hir.find(parent_id) {
Some(Node::NodeItem(&Item { ref name, .. })) |
Some(Node::NodeTraitItem(&TraitItem { ref name, .. })) |
Some(Node::NodeImplItem(&ImplItem { ref name, .. })) => Some(*name),
/// Get a parent expressions if any – this is useful to constrain a lint.
pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> {
- let map = &cx.tcx.map;
+ let map = &cx.tcx.hir;
let node_id: NodeId = e.id;
let parent_id: NodeId = map.get_parent_node(node_id);
if node_id == parent_id {
}
pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
- let map = &cx.tcx.map;
+ let map = &cx.tcx.hir;
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(_, _, _, _, _, eid), .. }) => {
- match cx.tcx.map.body(eid).value.node {
+ match cx.tcx.hir.body(eid).value.node {
ExprBlock(ref block) => Some(block),
_ => None,
}
/// 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> {
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item);
- let fn_def_id = cx.tcx.map.local_def_id(fn_item);
+ let fn_def_id = cx.tcx.hir.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()
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.map.get_parent(expr.id)),
+ is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)), cx.tcx.hir.get_parent(expr.id)),
], {
// report the error around the `vec!` not inside `<std macros>:`
let span = cx.sess().codemap().source_callsite(arg.span);
--- /dev/null
+#![feature(plugin)]
+#![plugin(clippy)]
+
+#![allow(dead_code)]
+#![deny(empty_enum)]
+
+enum Empty {} //~ ERROR enum with no variants
+ //~^ HELP consider using the uninhabited type `!` or a wrapper around it
+
+fn main() {
+}
use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants
-enum Enum {}
+enum Enum {
+ _Foo,
+}
use self::Enum::*; //~ ERROR: don't use glob imports for enum variants
/// Checks implementation of `ITER_NTH` lint
fn iter_nth() {
let mut some_vec = vec![0, 1, 2, 3];
+ let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
{
//~^ERROR called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable
let bad_slice = &some_vec[..].iter().nth(3);
//~^ERROR called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
+ let bad_boxed_slice = boxed_slice.iter().nth(3);
+ //~^ERROR called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
let bad_vec_deque = some_vec_deque.iter().nth(3);
//~^ERROR called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable
}
/// Checks implementation of `GET_UNWRAP` lint
fn get_unwrap() {
+ let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let mut some_slice = &mut [0, 1, 2, 3];
let mut some_vec = vec![0, 1, 2, 3];
let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
{ // Test `get().unwrap()`
+ let _ = boxed_slice.get(1).unwrap();
+ //~^ERROR called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+ //~|HELP try this
+ //~|SUGGESTION boxed_slice[1]
let _ = some_slice.get(0).unwrap();
//~^ERROR called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
//~|HELP try this
}
{ // Test `get_mut().unwrap()`
+ *boxed_slice.get_mut(0).unwrap() = 1;
+ //~^ERROR called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+ //~|HELP try this
+ //~|SUGGESTION &mut boxed_slice[0]
*some_slice.get_mut(0).unwrap() = 1;
//~^ERROR called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
//~|HELP try this