diff --git a/.gitignore b/.gitignore index a6b636709c52..33ecb63593cd 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ Cargo.lock # gh pages docs util/gh-pages/lints.json + +# rustfmt backups +*.rs.bk diff --git a/.travis.yml b/.travis.yml index ef97bd57e2f5..3c226c879f26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,11 +17,16 @@ install: - nvm install stable - nvm use stable - npm install remark-cli remark-lint + # || true, because we cache rustfmt and don't want to crash on the next travis run + # due to rustfmt already being installed + - (cargo install rustfmt || true) script: - remark -f README.md > /dev/null - python util/update_lints.py -c - set -e + - PATH=$PATH:~/.cargo/bin cargo fmt -- --write-mode=diff + - cd clippy_lints && PATH=$PATH:~/.cargo/bin cargo fmt -- --write-mode=diff && cd .. - cargo build --features debugging - cargo test --features debugging - mkdir -p ~/rust/cargo/bin diff --git a/CHANGELOG.md b/CHANGELOG.md index c08d567ec52f..51381a6eb024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.104 — 2016-12-15 +* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)* + ## 0.0.103 — 2016-11-25 * Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)* @@ -260,6 +263,7 @@ All notable changes to this project will be documented in this file. [`crosspointer_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#crosspointer_transmute [`cyclomatic_complexity`]: https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity [`deprecated_semver`]: https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver +[`deref_addrof`]: https://github.com/Manishearth/rust-clippy/wiki#deref_addrof [`derive_hash_xor_eq`]: https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq [`diverging_sub_expression`]: https://github.com/Manishearth/rust-clippy/wiki#diverging_sub_expression [`doc_markdown`]: https://github.com/Manishearth/rust-clippy/wiki#doc_markdown @@ -353,6 +357,7 @@ All notable changes to this project will be documented in this file. [`print_stdout`]: https://github.com/Manishearth/rust-clippy/wiki#print_stdout [`print_with_newline`]: https://github.com/Manishearth/rust-clippy/wiki#print_with_newline [`ptr_arg`]: https://github.com/Manishearth/rust-clippy/wiki#ptr_arg +[`pub_enum_variant_names`]: https://github.com/Manishearth/rust-clippy/wiki#pub_enum_variant_names [`range_step_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero [`range_zip_with_len`]: https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len [`redundant_closure`]: https://github.com/Manishearth/rust-clippy/wiki#redundant_closure diff --git a/Cargo.toml b/Cargo.toml index a21fd9e12274..0b1d7fd8671b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.103" +version = "0.0.104" authors = [ "Manish Goregaokar ", "Andre Bogus ", @@ -25,11 +25,11 @@ test = false [dependencies] # begin automatic update -clippy_lints = { version = "0.0.103", path = "clippy_lints" } +clippy_lints = { version = "0.0.104", path = "clippy_lints" } # end automatic update [dev-dependencies] -compiletest_rs = "0.2.1" +compiletest_rs = "0.2.5" lazy_static = "0.1.15" regex = "0.1.71" rustc-serialize = "0.3" diff --git a/README.md b/README.md index 01069fc8b8c6..15751a0d3d0b 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,79 @@ Table of contents: ## Usage +Since this is a tool for helping the developer of a library or application +write better code, it is recommended not to include clippy as a hard dependency. +Options include using it as an optional dependency, as a cargo subcommand, or +as an included feature during build. All of these options are detailed below. + As a general rule clippy will only work with the *latest* Rust nightly for now. +### Optional dependency + +If you want to make clippy an optional dependency, you can do the following: + +In your `Cargo.toml`: + +```toml +[dependencies] +clippy = {version = "*", optional = true} + +[features] +default = [] +``` + +And, in your `main.rs` or `lib.rs`: + +```rust +#![cfg_attr(feature="clippy", feature(plugin))] + +#![cfg_attr(feature="clippy", plugin(clippy))] +``` + +Then build by enabling the feature: `cargo build --features "clippy"` + +Instead of adding the `cfg_attr` attributes you can also run clippy on demand: +`cargo rustc --features clippy -- -Z no-trans -Z extra-plugins=clippy` +(the `-Z no trans`, while not neccessary, will stop the compilation process after +typechecking (and lints) have completed, which can significantly reduce the runtime). + +### As a cargo subcommand (`cargo clippy`) + +An alternate way to use clippy is by installing clippy through cargo as a cargo +subcommand. + +```terminal +cargo install clippy +``` + +Now you can run clippy by invoking `cargo clippy`, or +`rustup run nightly cargo clippy` directly from a directory that is usually +compiled with stable. + +In case you are not using rustup, you need to set the environment flag +`SYSROOT` during installation so clippy knows where to find `librustc` and +similar crates. + +```terminal +SYSROOT=/path/to/rustc/sysroot cargo install clippy +``` + +### Running clippy from the command line without installing + +To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` +in your code, you can use: + +```terminal +cargo rustc -- -L /path/to/clippy_so -Z extra-plugins=clippy +``` + +*[Note](https://github.com/Manishearth/rust-clippy/wiki#a-word-of-warning):* +Be sure that clippy was compiled with the same version of rustc that cargo invokes here! + ### As a Compiler Plugin +*Note:* This is not a recommended installation method. + Since stable Rust is backwards compatible, you should be able to compile your stable programs with nightly Rust with clippy plugged in to circumvent this. @@ -63,68 +132,6 @@ src/main.rs:8:5: 11:6 help: Try if let Some(y) = x { println!("{:?}", y) } ``` -### As a cargo subcommand (`cargo clippy`) - -An alternate way to use clippy is by installing clippy through cargo as a cargo -subcommand. - -```terminal -cargo install clippy -``` - -Now you can run clippy by invoking `cargo clippy`, or -`rustup run nightly cargo clippy` directly from a directory that is usually -compiled with stable. - -In case you are not using rustup, you need to set the environment flag -`SYSROOT` during installation so clippy knows where to find `librustc` and -similar crates. - -```terminal -SYSROOT=/path/to/rustc/sysroot cargo install clippy -``` - -### Running clippy from the command line without installing - -To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` -in your code, you can use: - -```terminal -cargo rustc -- -L /path/to/clippy_so -Z extra-plugins=clippy -``` - -*[Note](https://github.com/Manishearth/rust-clippy/wiki#a-word-of-warning):* -Be sure that clippy was compiled with the same version of rustc that cargo invokes here! - -### Optional dependency - -If you want to make clippy an optional dependency, you can do the following: - -In your `Cargo.toml`: - -```toml -[dependencies] -clippy = {version = "*", optional = true} - -[features] -default = [] -``` - -And, in your `main.rs` or `lib.rs`: - -```rust -#![cfg_attr(feature="clippy", feature(plugin))] - -#![cfg_attr(feature="clippy", plugin(clippy))] -``` - -Then build by enabling the feature: `cargo build --features "clippy"` - -Instead of adding the `cfg_attr` attributes you can also run clippy on demand: -`cargo rustc --features clippy -- -Z no-trans -Z extra-plugins=clippy` -(the `-Z no trans`, while not neccessary, will stop the compilation process after -typechecking (and lints) have completed, which can significantly reduce the runtime). - ## Configuration Some lints can be configured in a `clippy.toml` file. It contains basic `variable = value` mapping eg. @@ -172,7 +179,7 @@ transparently: ## Lints -There are 178 lints included in this crate: +There are 180 lints included in this crate: name | default | triggers on -----------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------- @@ -204,6 +211,7 @@ name [crosspointer_transmute](https://github.com/Manishearth/rust-clippy/wiki#crosspointer_transmute) | warn | transmutes that have to or from types that are a pointer to the other [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | use of `#[deprecated(since = "x")]` where x is not semver +[deref_addrof](https://github.com/Manishearth/rust-clippy/wiki#deref_addrof) | warn | use of `*&` or `*&mut` in an expression [derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly [diverging_sub_expression](https://github.com/Manishearth/rust-clippy/wiki#diverging_sub_expression) | warn | whether an expression contains a diverging sub expression [doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | presence of `_`, `::` or camel-case outside backticks in documentation @@ -297,6 +305,7 @@ name [print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout [print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +[pub_enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#pub_enum_variant_names) | allow | enums where all variants share a prefix/postfix [range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator [range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 872c4152ae73..faf86875f40d 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.0.103" +version = "0.0.104" # end automatic update authors = [ "Manish Goregaokar ", diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index c57122eeef91..7131e609715b 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -59,8 +59,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprLit(ref lit) = e.node { check_lit(cx, lit, e); } @@ -85,7 +85,9 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &symbol::Symbol, module: &s APPROX_CONSTANT, e.span, &format!("approximate value of `{}::consts::{}` found. \ - Consider using it directly", module, &name)); + Consider using it directly", + module, + &name)); return; } } diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 7c1042e52374..109f045b619b 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -47,8 +47,8 @@ impl LintPass for Arithmetic { } } -impl LateLintPass for Arithmetic { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { if self.span.is_some() { return; } @@ -67,7 +67,7 @@ impl LateLintPass for Arithmetic { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.span = Some(expr.span); } - } + }, hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { let ty = cx.tcx.tables().expr_ty(arg); if ty.is_integral() { @@ -77,12 +77,12 @@ impl LateLintPass for Arithmetic { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.span = Some(expr.span); } - } + }, _ => (), } } - fn check_expr_post(&mut self, _: &LateContext, expr: &hir::Expr) { + fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { if Some(expr.span) == self.span { self.span = None; } diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index eb84f459e985..de13c0264e50 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -55,8 +55,8 @@ impl LintPass for ArrayIndexing { } } -impl LateLintPass for ArrayIndexing { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprIndex(ref array, ref index) = e.node { // Array with known size can be checked statically let ty = cx.tcx.tables().expr_ty(array); @@ -107,9 +107,12 @@ impl LateLintPass for ArrayIndexing { } /// Returns an option containing a tuple with the start and end (exclusive) of the range. -fn to_const_range(start: Option>, end: Option>, limits: RangeLimits, - array_size: ConstInt) - -> Option<(ConstInt, ConstInt)> { +fn to_const_range( + start: Option>, + end: Option>, + limits: RangeLimits, + array_size: ConstInt +) -> Option<(ConstInt, ConstInt)> { let start = match start { Some(Some(ConstVal::Integral(x))) => x, Some(_) => return None, @@ -123,7 +126,7 @@ fn to_const_range(start: Option>, end: Option> } else { x } - } + }, Some(_) => return None, None => array_size, }; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 9e702fe3b4e3..122a600d7d38 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,5 +1,6 @@ use rustc::hir; use rustc::lint::*; +use syntax::ast; use utils::{span_lint_and_then, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait}; use utils::{higher, sugg}; @@ -66,8 +67,8 @@ impl LintPass for AssignOps { } } -impl LateLintPass for AssignOps { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { match expr.node { hir::ExprAssignOp(op, ref lhs, ref rhs) => { span_lint_and_then(cx, ASSIGN_OPS, expr.span, "assign operation detected", |db| { @@ -94,13 +95,13 @@ impl LateLintPass for AssignOps { expr.span, "variable appears on both sides of an assignment operation", |db| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), - snippet_opt(cx, rhs.span)) { - db.span_suggestion(expr.span, - "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); - } - }); + if let (Some(snip_a), Some(snip_r)) = + (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { + db.span_suggestion(expr.span, + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); + } + }); }; // lhs op= l op r if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) { @@ -112,7 +113,7 @@ impl LateLintPass for AssignOps { } } } - } + }, hir::ExprAssign(ref assignee, ref e) => { if let hir::ExprBinary(op, ref l, ref r) = e.node { let lint = |assignee: &hir::Expr, rhs: &hir::Expr| { @@ -125,7 +126,11 @@ impl LateLintPass for AssignOps { return; // implements_trait does not work with generics } macro_rules! ops { - ($op:expr, $cx:expr, $ty:expr, $rty:expr, $($trait_name:ident:$full_trait_name:ident),+) => { + ($op:expr, + $cx:expr, + $ty:expr, + $rty:expr, + $($trait_name:ident:$full_trait_name:ident),+) => { match $op { $(hir::$full_trait_name => { let [krate, module] = ::utils::paths::OPS_MODULE; @@ -135,6 +140,16 @@ impl LateLintPass for AssignOps { } else { 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); + // 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::Item_::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node, + trait_ref.path.def.def_id() == trait_id + ], { return; }} implements_trait($cx, $ty, trait_id, vec![$rty]) },)* _ => false, @@ -162,13 +177,13 @@ impl LateLintPass for AssignOps { expr.span, "manual implementation of an assign operation", |db| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), - snippet_opt(cx, rhs.span)) { - db.span_suggestion(expr.span, - "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); - } - }); + if let (Some(snip_a), Some(snip_r)) = + (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { + db.span_suggestion(expr.span, + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); + } + }); } }; // a = a op b @@ -181,13 +196,13 @@ impl LateLintPass for AssignOps { hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr => { lint(assignee, l); - } - _ => {} + }, + _ => {}, } } } - } - _ => {} + }, + _ => {}, } } } @@ -195,23 +210,7 @@ impl LateLintPass for AssignOps { fn is_commutative(op: hir::BinOp_) -> bool { use rustc::hir::BinOp_::*; match op { - BiAdd | - BiMul | - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr | - BiEq | - BiNe => true, - BiSub | - BiDiv | - BiRem | - BiShl | - BiShr | - BiLt | - BiLe | - BiGe | - BiGt => false, + BiAdd | BiMul | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr | BiEq | BiNe => true, + BiSub | BiDiv | BiRem | BiShl | BiShr | BiLt | BiLe | BiGe | BiGt => false, } } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2d9960c7e3d8..df6ef64a73f8 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -36,9 +36,11 @@ declare_lint! { /// **What it does:** Checks for `extern crate` and `use` items annotated with lint attributes /// -/// **Why is this bad?** Lint attributes have no effect on crate imports. Most likely a `!` was forgotten +/// **Why is this bad?** Lint attributes have no effect on crate imports. Most likely a `!` was +/// forgotten /// -/// **Known problems:** Technically one might allow `unused_import` on a `use` item, but it's easier to remove the unused item. +/// **Known problems:** Technically one might allow `unused_import` on a `use` item, +/// but it's easier to remove the unused item. /// /// **Example:** /// ```rust @@ -81,8 +83,8 @@ impl LintPass for AttrPass { } } -impl LateLintPass for AttrPass { - fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { + fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) { if let MetaItemKind::List(ref items) = attr.value.node { if items.is_empty() || attr.name() != "deprecated" { return; @@ -99,13 +101,13 @@ impl LateLintPass for AttrPass { } } - fn check_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if is_relevant_item(cx, item) { check_attrs(cx, item.span, &item.name, &item.attrs) } match item.node { ItemExternCrate(_) | - ItemUse(_) => { + ItemUse(_, _) => { for attr in &item.attrs { if let MetaItemKind::List(ref lint_list) = attr.value.node { match &*attr.name().as_str() { @@ -113,14 +115,16 @@ impl LateLintPass for AttrPass { // whitelist `unused_imports` and `deprecated` for lint in lint_list { if is_word(lint, "unused_imports") || is_word(lint, "deprecated") { - if let ItemUse(_) = item.node { + if let ItemUse(_, _) = item.node { return; } } } if let Some(mut sugg) = snippet_opt(cx, attr.span) { if sugg.len() > 1 { - span_lint_and_then(cx, USELESS_ATTRIBUTE, attr.span, + span_lint_and_then(cx, + USELESS_ATTRIBUTE, + attr.span, "useless lint attribute", |db| { sugg.insert(1, '!'); @@ -138,13 +142,13 @@ impl LateLintPass for AttrPass { } } - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) { if is_relevant_impl(cx, item) { check_attrs(cx, item.span, &item.name, &item.attrs) } } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { if is_relevant_trait(cx, item) { check_attrs(cx, item.span, &item.name, &item.attrs) } @@ -152,8 +156,8 @@ impl LateLintPass for AttrPass { } fn is_relevant_item(cx: &LateContext, item: &Item) -> bool { - if let ItemFn(_, _, _, _, _, ref expr) = item.node { - is_relevant_expr(cx, expr) + if let ItemFn(_, _, _, _, _, eid) = item.node { + is_relevant_expr(cx, cx.tcx.map.expr(eid)) } else { false } @@ -161,7 +165,7 @@ fn is_relevant_item(cx: &LateContext, item: &Item) -> bool { fn is_relevant_impl(cx: &LateContext, item: &ImplItem) -> bool { match item.node { - ImplItemKind::Method(_, ref expr) => is_relevant_expr(cx, expr), + ImplItemKind::Method(_, eid) => is_relevant_expr(cx, cx.tcx.map.expr(eid)), _ => false, } } @@ -169,7 +173,7 @@ fn is_relevant_impl(cx: &LateContext, item: &ImplItem) -> bool { fn is_relevant_trait(cx: &LateContext, item: &TraitItem) -> bool { match item.node { MethodTraitItem(_, None) => true, - MethodTraitItem(_, Some(ref expr)) => is_relevant_expr(cx, expr), + MethodTraitItem(_, Some(eid)) => is_relevant_expr(cx, cx.tcx.map.expr(eid)), _ => false, } } @@ -181,7 +185,7 @@ fn is_relevant_block(cx: &LateContext, block: &Block) -> bool { StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { return is_relevant_expr(cx, expr); - } + }, } } block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, e)) @@ -191,15 +195,16 @@ fn is_relevant_expr(cx: &LateContext, expr: &Expr) -> bool { match expr.node { ExprBlock(ref block) => is_relevant_block(cx, block), ExprRet(Some(ref e)) => is_relevant_expr(cx, e), - ExprRet(None) | ExprBreak(_, None) => false, + ExprRet(None) | + ExprBreak(_, None) => false, ExprCall(ref path_expr, _) => { - if let ExprPath(..) = path_expr.node { - let fun_id = resolve_node(cx, path_expr.id).expect("function should be resolved").def_id(); + if let ExprPath(ref qpath) = path_expr.node { + let fun_id = resolve_node(cx, qpath, path_expr.id).def_id(); !match_def_path(cx, fun_id, &paths::BEGIN_PANIC) } else { true } - } + }, _ => true, } } diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index b021079fd975..5b860d8cedc7 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,5 +1,5 @@ use rustc::hir::*; -use rustc::hir::def::{Def, PathResolution}; +use rustc::hir::def::Def; use rustc::lint::*; use rustc_const_eval::lookup_const_by_id; use syntax::ast::LitKind; @@ -79,8 +79,8 @@ impl LintPass for BitMask { } } -impl LateLintPass for BitMask { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if cmp.node.is_comparison() { if let Some(cmp_opt) = fetch_int_literal(cx, right) { @@ -134,7 +134,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } - } + }, BiBitOr => { if mask_value | cmp_value != cmp_value { span_lint(cx, @@ -144,10 +144,10 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: mask_value, cmp_value)); } - } + }, _ => (), } - } + }, BiLt | BiGe => { match bit_op { BiBitAnd => { @@ -161,7 +161,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } - } + }, BiBitOr => { if mask_value >= cmp_value { span_lint(cx, @@ -173,11 +173,11 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: } else { check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); } - } + }, BiBitXor => check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"), _ => (), } - } + }, BiLe | BiGt => { match bit_op { BiBitAnd => { @@ -191,7 +191,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } - } + }, BiBitOr => { if mask_value > cmp_value { span_lint(cx, @@ -203,11 +203,11 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: } else { check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); } - } + }, BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), _ => (), } - } + }, _ => (), } } @@ -244,20 +244,15 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option { } else { None } - } - ExprPath(_, _) => { - { - // Important to let the borrow expire before the const lookup to avoid double - // borrowing. - let def_map = cx.tcx.def_map.borrow(); - match def_map.get(&lit.id) { - Some(&PathResolution { base_def: Def::Const(def_id), .. }) => Some(def_id), - _ => None, - } + }, + ExprPath(ref qpath) => { + let def = cx.tcx.tables().qpath_def(qpath, lit.id); + if let Def::Const(def_id) = def { + lookup_const_by_id(cx.tcx, def_id, None).and_then(|(l, _ty)| fetch_int_literal(cx, l)) + } else { + None } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None)) - .and_then(|(l, _ty)| fetch_int_literal(cx, l)) - } + }, _ => None, } } diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 55d0efd35362..2f9a50fe3dac 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -37,9 +37,9 @@ impl LintPass for BlackListedName { } } -impl LateLintPass for BlackListedName { - fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { - if let PatKind::Binding(_, ref ident, _) = pat.node { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlackListedName { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { + if let PatKind::Binding(_, _, ref ident, _) = pat.node { if self.blacklist.iter().any(|s| s == &*ident.node.as_str()) { span_lint(cx, BLACKLISTED_NAME, diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 704729c4e36e..2f9a6b161585 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr}; +use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; use utils::*; /// **What it does:** Checks for `if` conditions that use blocks to contain an @@ -49,13 +49,15 @@ impl LintPass for BlockInIfCondition { } } -struct ExVisitor<'v> { - found_block: Option<&'v Expr>, +struct ExVisitor<'a, 'tcx: 'a> { + found_block: Option<&'tcx Expr>, + cx: &'a LateContext<'a, 'tcx>, } -impl<'v> Visitor<'v> for ExVisitor<'v> { - fn visit_expr(&mut self, expr: &'v Expr) { - if let ExprClosure(_, _, ref expr, _) = expr.node { +impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { + if let ExprClosure(_, _, eid, _) = expr.node { + let expr = self.cx.tcx.map.expr(eid); if matches!(expr.node, ExprBlock(_)) { self.found_block = Some(expr); return; @@ -63,14 +65,17 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } const BRACED_EXPR_MESSAGE: &'static str = "omit braces around single expression condition"; const COMPLEX_BLOCK_MESSAGE: &'static str = "in an 'if' condition, avoid complex blocks or closures with blocks; \ instead, move the block or closure higher and bind it with a 'let'"; -impl LateLintPass for BlockInIfCondition { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprIf(ref check, ref then, _) = expr.node { if let ExprBlock(ref block) = check.node { if block.rules == DefaultBlock { @@ -105,7 +110,10 @@ impl LateLintPass for BlockInIfCondition { } } } else { - let mut visitor = ExVisitor { found_block: None }; + let mut visitor = ExVisitor { + found_block: None, + cx: cx, + }; walk_expr(&mut visitor, check); if let Some(block) = visitor.found_block { span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 21ac913253b2..979b62f8ce7e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -53,13 +53,15 @@ impl LintPass for NonminimalBool { } } -impl LateLintPass for NonminimalBool { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - NonminimalBoolVisitor(cx).visit_item(item) +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonminimalBool { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { + NonminimalBoolVisitor { cx: cx }.visit_item(item) } } -struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); +struct NonminimalBoolVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, +} use quine_mc_cluskey::Bool; struct Hir2Qmm<'a, 'tcx: 'a, 'v> { @@ -92,14 +94,14 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)), _ => (), } - } + }, ExprLit(ref lit) => { match lit.node { LitKind::Bool(true) => return Ok(Bool::True), LitKind::Bool(false) => return Ok(Bool::False), _ => (), } - } + }, _ => (), } } @@ -127,7 +129,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { BiLe => mk_expr(BiGt), _ => continue, } - } + }, _ => continue, }; if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { @@ -154,17 +156,17 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { True => { s.push_str("true"); s - } + }, False => { s.push_str("false"); s - } + }, Not(ref inner) => { match **inner { And(_) | Or(_) => { s.push('!'); recurse(true, cx, inner, terminals, s) - } + }, Term(n) => { if let ExprBinary(binop, ref lhs, ref rhs) = terminals[n as usize].node { let op = match binop.node { @@ -177,7 +179,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { _ => { s.push('!'); return recurse(true, cx, inner, terminals, s); - } + }, }; s.push_str(&snip(lhs)); s.push_str(op); @@ -187,13 +189,13 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push('!'); recurse(false, cx, inner, terminals, s) } - } + }, _ => { s.push('!'); recurse(false, cx, inner, terminals, s) - } + }, } - } + }, And(ref v) => { if brackets { s.push('('); @@ -215,7 +217,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push(')'); } s - } + }, Or(ref v) => { if brackets { s.push('('); @@ -229,7 +231,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push(')'); } s - } + }, Term(n) => { if brackets { if let ExprBinary(..) = terminals[n as usize].node { @@ -243,7 +245,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { } } s - } + }, } } recurse(false, cx, suggestion, terminals, String::new()) @@ -260,13 +262,13 @@ fn simple_negate(b: Bool) -> Bool { *el = simple_negate(::std::mem::replace(el, True)); } Or(v) - } + }, Or(mut v) => { for el in &mut v { *el = simple_negate(::std::mem::replace(el, True)); } And(v) - } + }, Not(inner) => *inner, } } @@ -288,13 +290,13 @@ fn terminal_stats(b: &Bool) -> Stats { _ => stats.negations += 1, } recurse(inner, stats); - } + }, And(ref v) | Or(ref v) => { stats.ops += v.len() - 1; for inner in v { recurse(inner, stats); } - } + }, Term(n) => stats.terminals[n as usize] += 1, } } @@ -308,7 +310,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { fn bool_expr(&self, e: &Expr) { let mut h2q = Hir2Qmm { terminals: Vec::new(), - cx: self.0, + cx: self.cx, }; if let Ok(expr) = h2q.run(e) { @@ -323,7 +325,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { let mut simplified = expr.simplify(); for simple in Bool::Not(Box::new(expr.clone())).simplify() { match simple { - Bool::Not(_) | Bool::True | Bool::False => {} + Bool::Not(_) | Bool::True | Bool::False => {}, _ => simplified.push(Bool::Not(Box::new(simple.clone()))), } let simple_negated = simple_negate(simple); @@ -343,7 +345,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { continue 'simplified; } if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { - span_lint_and_then(self.0, + span_lint_and_then(self.cx, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", @@ -353,7 +355,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { outer expression"); db.span_suggestion(e.span, "it would look like the following", - suggest(self.0, suggestion, &h2q.terminals)); + suggest(self.cx, suggestion, &h2q.terminals)); }); // don't also lint `NONMINIMAL_BOOL` return; @@ -370,13 +372,13 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } if !improvements.is_empty() { - span_lint_and_then(self.0, + span_lint_and_then(self.cx, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| { for suggestion in &improvements { - db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals)); + db.span_suggestion(e.span, "try", suggest(self.cx, suggestion, &h2q.terminals)); } }); } @@ -384,21 +386,24 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } -impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> { - fn visit_expr(&mut self, e: &'v Expr) { - if in_macro(self.0, e.span) { +impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr) { + if in_macro(self.cx, e.span) { return; } match e.node { ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e), ExprUnary(UnNot, ref inner) => { - if self.0.tcx.tables.borrow().node_types[&inner.id].is_bool() { + if self.cx.tcx.tables.borrow().node_types[&inner.id].is_bool() { self.bool_expr(e); } else { walk_expr(self, e); } - } + }, _ => walk_expr(self, e), } } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 9d23d32c81ae..85bd419df732 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -2,7 +2,7 @@ //! //! For example, the lint would catch: //! -//! ```rust +//! ```rust,ignore //! if x { //! if y { //! println!("Hello world"); @@ -28,7 +28,7 @@ use utils::sugg::Sugg; /// **Known problems:** None. /// /// **Example:** -/// ```rust +/// ```rust,ignore /// if x { /// if y { /// … @@ -48,7 +48,7 @@ use utils::sugg::Sugg; /// /// Should be written: /// -/// ```rust +/// ```rust.ignore /// if x && y { /// … /// } @@ -92,10 +92,10 @@ fn check_if(cx: &EarlyContext, expr: &ast::Expr) { } else { check_collapsible_no_if_let(cx, expr, check, then); } - } + }, ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => { check_collapsible_maybe_if_let(cx, else_); - } + }, _ => (), } } @@ -120,12 +120,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) { }} } -fn check_collapsible_no_if_let( - cx: &EarlyContext, - expr: &ast::Expr, - check: &ast::Expr, - then: &ast::Block, -) { +fn check_collapsible_no_if_let(cx: &EarlyContext, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) { if_let_chain! {[ let Some(inner) = expr_block(then), let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node, @@ -145,13 +140,14 @@ fn check_collapsible_no_if_let( }} } -/// If the block contains only one expression, returns it. +/// If the block contains only one expression, return it. fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { let mut it = block.stmts.iter(); if let (Some(stmt), None) = (it.next(), it.next()) { match stmt.node { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr), + ast::StmtKind::Expr(ref expr) | + ast::StmtKind::Semi(ref expr) => Some(expr), _ => None, } } else { diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 89c57bba233b..44288e7d7fcd 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,7 +1,7 @@ #![allow(cast_possible_truncation)] use rustc::lint::LateContext; -use rustc::hir::def::{Def, PathResolution}; +use rustc::hir::def::Def; use rustc_const_eval::lookup_const_by_id; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::hir::*; @@ -10,7 +10,7 @@ use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; use std::mem; use std::rc::Rc; -use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy}; +use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy, NodeId}; use syntax::ptr::P; #[derive(Debug, Copy, Clone)] @@ -75,18 +75,16 @@ impl PartialEq for Constant { (&Constant::Char(l), &Constant::Char(r)) => l == r, (&Constant::Int(l), &Constant::Int(r)) => { l.is_negative() == r.is_negative() && l.to_u64_unchecked() == r.to_u64_unchecked() - } + }, (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have // `Fw32 == Fw64` so don’t compare them match (ls.parse::(), rs.parse::()) { // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs - (Ok(l), Ok(r)) => unsafe { - mem::transmute::(l) == mem::transmute::(r) - }, + (Ok(l), Ok(r)) => unsafe { mem::transmute::(l) == mem::transmute::(r) }, _ => false, } - } + }, (&Constant::Bool(l), &Constant::Bool(r)) => l == r, (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l == r, (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv, @@ -104,34 +102,34 @@ impl Hash for Constant { Constant::Str(ref s, ref k) => { s.hash(state); k.hash(state); - } + }, Constant::Binary(ref b) => { b.hash(state); - } + }, Constant::Char(c) => { c.hash(state); - } + }, Constant::Int(i) => { i.to_u64_unchecked().hash(state); i.is_negative().hash(state); - } + }, Constant::Float(ref f, _) => { // don’t use the width here because of PartialEq implementation if let Ok(f) = f.parse::() { unsafe { mem::transmute::(f) }.hash(state); } - } + }, Constant::Bool(b) => { b.hash(state); - } + }, Constant::Vec(ref v) | Constant::Tuple(ref v) => { v.hash(state); - } + }, Constant::Repeat(ref c, l) => { c.hash(state); l.hash(state); - } + }, } } } @@ -145,19 +143,21 @@ impl PartialOrd for Constant { } else { None } - } + }, (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), (&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)), (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { match (ls.parse::(), rs.parse::()) { - (Ok(ref l), Ok(ref r)) => match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) { - // Check for comparison of -0.0 and 0.0 - (Some(Ordering::Equal), false) => None, - (x, _) => x + (Ok(ref l), Ok(ref r)) => { + match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) { + // Check for comparison of -0.0 and 0.0 + (Some(Ordering::Equal), false) => None, + (x, _) => x, + } }, _ => None, } - } + }, (&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)), (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r), @@ -166,7 +166,7 @@ impl PartialOrd for Constant { Some(Equal) => Some(ls.cmp(rs)), x => x, } - } + }, _ => None, //TODO: Are there any useful inter-type orderings? } } @@ -187,14 +187,14 @@ pub fn lit_to_constant(lit: &LitKind) -> Constant { LitKind::Int(value, LitIntType::Unsigned(UintTy::U64)) => Constant::Int(ConstInt::U64(value as u64)), LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => { Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32))) - } + }, LitKind::Int(value, LitIntType::Signed(IntTy::I8)) => Constant::Int(ConstInt::I8(value as i8)), LitKind::Int(value, LitIntType::Signed(IntTy::I16)) => Constant::Int(ConstInt::I16(value as i16)), LitKind::Int(value, LitIntType::Signed(IntTy::I32)) => Constant::Int(ConstInt::I32(value as i32)), LitKind::Int(value, LitIntType::Signed(IntTy::I64)) => Constant::Int(ConstInt::I64(value as i64)), LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => { Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32))) - } + }, LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), LitKind::Bool(b) => Constant::Bool(b), @@ -252,7 +252,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { /// simple constant folding: Insert an expression, get a constant or none. fn expr(&mut self, e: &Expr) -> Option { match e.node { - ExprPath(_, _) => self.fetch_path(e), + ExprPath(ref qpath) => self.fetch_path(qpath, e.id), ExprBlock(ref block) => self.block(block), ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), @@ -260,7 +260,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprRepeat(ref value, ref number) => { self.binop_apply(value, number, |v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize))) - } + }, ExprUnary(op, ref operand) => { self.expr(operand).and_then(|o| { match op { @@ -269,7 +269,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { UnDeref => Some(o), } }) - } + }, ExprBinary(op, ref left, ref right) => self.binop(op, left, right), // TODO: add other expressions _ => None, @@ -280,26 +280,30 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { /// non-constant part fn multi(&mut self, vec: &[Expr]) -> Option> { vec.iter() - .map(|elem| self.expr(elem)) - .collect::>() + .map(|elem| self.expr(elem)) + .collect::>() } /// lookup a possibly constant expression from a ExprPath - fn fetch_path(&mut self, e: &Expr) -> Option { + fn fetch_path(&mut self, qpath: &QPath, id: NodeId) -> Option { if let Some(lcx) = self.lcx { - let mut maybe_id = None; - if let Some(&PathResolution { base_def: Def::Const(id), .. }) = lcx.tcx.def_map.borrow().get(&e.id) { - maybe_id = Some(id); - } - // separate if lets to avoid double borrowing the def_map - if let Some(id) = maybe_id { - if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None) { - let ret = self.expr(const_expr); - if ret.is_some() { - self.needed_resolution = true; + let def = lcx.tcx.tables().qpath_def(qpath, id); + match def { + Def::Const(def_id) | + Def::AssociatedConst(def_id) => { + let substs = Some(lcx.tcx + .tables() + .node_id_item_substs(id) + .unwrap_or_else(|| lcx.tcx.intern_substs(&[]))); + if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, def_id, substs) { + let ret = self.expr(const_expr); + if ret.is_some() { + self.needed_resolution = true; + } + return ret; } - return ret; - } + }, + _ => {}, } } None diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index b46fda3d2f20..11b85edba3e6 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -109,8 +109,8 @@ impl LintPass for CopyAndPaste { } } -impl LateLintPass for CopyAndPaste { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if !in_macro(cx, expr.span) { // skip ifs directly in else, it will be checked in the parent if if let Some(&Expr { node: ExprIf(_, _, Some(ref else_expr)), .. }) = get_parent_expr(cx, expr) { @@ -204,8 +204,11 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { if let PatKind::Wild = j.pats[0].node { // if the last arm is _, then i could be integrated into _ - // note that i.pats[0] cannot be _, because that would mean that we're hiding all the subsequent arms, and rust won't compile - db.span_note(i.body.span, &format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", lhs)); + // note that i.pats[0] cannot be _, because that would mean that we're + // hiding all the subsequent arms, and rust won't compile + db.span_note(i.body.span, + &format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", + lhs)); } else { db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs)); } @@ -245,7 +248,11 @@ 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> { - fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap>) { + fn bindings_impl<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + pat: &Pat, + map: &mut HashMap> + ) { match pat.node { PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), @@ -253,25 +260,25 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap { + }, + PatKind::Binding(_, _, ref ident, ref as_pat) => { if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { v.insert(cx.tcx.tables().pat_ty(pat)); } if let Some(ref as_pat) = *as_pat { bindings_impl(cx, as_pat, map); } - } + }, PatKind::Struct(_, ref fields, _) => { for pat in fields { bindings_impl(cx, &pat.node.pat, map); } - } + }, PatKind::Tuple(ref fields, _) => { for pat in fields { bindings_impl(cx, pat, map); } - } + }, PatKind::Slice(ref lhs, ref mid, ref rhs) => { for pat in lhs { bindings_impl(cx, pat, map); @@ -282,7 +289,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> return Some((o, expr)); } } - } + }, Entry::Vacant(v) => { v.insert(vec![expr]); - } + }, } } diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index f7758e3af231..897a578f19a7 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -4,7 +4,7 @@ use rustc::cfg::CFG; use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr}; +use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; use syntax::ast::Attribute; use syntax::attr; use syntax::codemap::Span; @@ -42,7 +42,7 @@ impl LintPass for CyclomaticComplexity { } impl CyclomaticComplexity { - fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, expr: &Expr, span: Span) { + fn check<'a, 'tcx: 'a>(&mut self, cx: &'a LateContext<'a, 'tcx>, expr: &'tcx Expr, span: Span) { if in_macro(cx, span) { return; } @@ -60,7 +60,7 @@ impl CyclomaticComplexity { divergence: 0, short_circuits: 0, returns: 0, - tcx: &cx.tcx, + cx: cx, }; helper.visit_expr(expr); let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; @@ -90,45 +90,45 @@ impl CyclomaticComplexity { } } -impl LateLintPass for CyclomaticComplexity { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemFn(_, _, _, _, _, ref expr) = item.node { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { + if let ItemFn(_, _, _, _, _, eid) = item.node { if !attr::contains_name(&item.attrs, "test") { - self.check(cx, expr, item.span); + self.check(cx, cx.tcx.map.expr(eid), item.span); } } } - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if let ImplItemKind::Method(_, ref expr) = item.node { - self.check(cx, expr, item.span); + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) { + if let ImplItemKind::Method(_, eid) = item.node { + self.check(cx, cx.tcx.map.expr(eid), item.span); } } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - if let MethodTraitItem(_, Some(ref expr)) = item.node { - self.check(cx, expr, item.span); + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { + if let MethodTraitItem(_, Some(eid)) = item.node { + self.check(cx, cx.tcx.map.expr(eid), item.span); } } - fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); } - fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); } } -struct CCHelper<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { +struct CCHelper<'a, 'tcx: 'a> { match_arms: u64, divergence: u64, returns: u64, short_circuits: u64, // && and || - tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, + cx: &'a LateContext<'a, 'tcx>, } -impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { - fn visit_expr(&mut self, e: &'a Expr) { +impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr) { match e.node { ExprMatch(_, ref arms, _) => { walk_expr(self, e); @@ -136,18 +136,18 @@ impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { if arms_n > 1 { self.match_arms += arms_n - 2; } - } + }, ExprCall(ref callee, _) => { walk_expr(self, e); - let ty = self.tcx.tables().node_id_to_type(callee.id); + let ty = self.cx.tcx.tables().node_id_to_type(callee.id); match ty.sty { ty::TyFnDef(_, _, ty) | - ty::TyFnPtr(ty) if ty.sig.skip_binder().output.sty == ty::TyNever => { + ty::TyFnPtr(ty) if ty.sig.skip_binder().output().sty == ty::TyNever => { self.divergence += 1; - } + }, _ => (), } - } + }, ExprClosure(..) => (), ExprBinary(op, _, _) => { walk_expr(self, e); @@ -155,11 +155,14 @@ impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { BiAnd | BiOr => self.short_circuits += 1, _ => (), } - } + }, ExprRet(_) => self.returns += 1, _ => walk_expr(self, e), } } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } } #[cfg(feature="debugging")] diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 59687aa191be..cda82f46434e 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::hir::*; use syntax::codemap::Span; use utils::paths; -use utils::{is_automatically_derived, match_path, span_lint_and_then}; +use utils::{is_automatically_derived, span_lint_and_then, match_path_old}; /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` /// explicitly. @@ -70,8 +70,8 @@ impl LintPass for Derive { } } -impl LateLintPass for Derive { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node { let ty = cx.tcx.item_type(cx.tcx.map.local_def_id(item.id)); let is_automatically_derived = is_automatically_derived(&*item.attrs); @@ -86,10 +86,15 @@ impl LateLintPass for Derive { } /// Implementation of the `DERIVE_HASH_XOR_EQ` lint. -fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>, - hash_is_automatically_derived: bool) { +fn check_hash_peq<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + span: Span, + trait_ref: &TraitRef, + ty: ty::Ty<'tcx>, + hash_is_automatically_derived: bool +) { if_let_chain! {[ - match_path(&trait_ref.path, &paths::HASH), + match_path_old(&trait_ref.path, &paths::HASH), let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() ], { let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id); @@ -131,7 +136,7 @@ fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_re /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { - if match_path(&trait_ref.path, &paths::CLONE_TRAIT) { + if match_path_old(&trait_ref.path, &paths::CLONE_TRAIT) { let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); let subst_ty = ty.subst(cx.tcx, parameter_environment.free_substs); @@ -149,18 +154,18 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref match field.ty(cx.tcx, substs).sty { TypeVariants::TyArray(_, size) if size > 32 => { return; - } + }, TypeVariants::TyFnPtr(..) => { return; - } + }, TypeVariants::TyTuple(tys) if tys.len() > 12 => { return; - } + }, _ => (), } } } - } + }, _ => (), } @@ -169,7 +174,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref item.span, "you are implementing `Clone` explicitly on a `Copy` type", |db| { - db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); - }); + db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); + }); } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 4183632543b7..20c82ee46607 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -64,26 +64,21 @@ pub fn strip_doc_comment_decoration((comment, span): (String, Span)) -> Vec<(Str const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"]; for prefix in ONELINERS { if comment.starts_with(*prefix) { - return vec![( - comment[prefix.len()..].to_owned(), - Span { lo: span.lo + BytePos(prefix.len() as u32), ..span } - )]; + return vec![(comment[prefix.len()..].to_owned(), + Span { lo: span.lo + BytePos(prefix.len() as u32), ..span })]; } } if comment.starts_with("/*") { - return comment[3..comment.len() - 2].lines().map(|line| { - let offset = line.as_ptr() as usize - comment.as_ptr() as usize; - debug_assert_eq!(offset as u32 as usize, offset); + return comment[3..comment.len() - 2] + .lines() + .map(|line| { + let offset = line.as_ptr() as usize - comment.as_ptr() as usize; + debug_assert_eq!(offset as u32 as usize, offset); - ( - line.to_owned(), - Span { - lo: span.lo + BytePos(offset as u32), - ..span - } - ) - }).collect(); + (line.to_owned(), Span { lo: span.lo + BytePos(offset as u32), ..span }) + }) + .collect(); } panic!("not a doc-comment: {}", comment); @@ -273,7 +268,9 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)] } lookup_parser = parser.clone(); - if let (Some((false, $c)), Some((false, $c))) = (lookup_parser.next(), lookup_parser.next()) { + let a = lookup_parser.next(); + let b = lookup_parser.next(); + if let (Some((false, $c)), Some((false, $c))) = (a, b) { let mut close_count = 3; while let Some((false, $c)) = lookup_parser.next() { close_count += 1; @@ -299,16 +296,17 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)] match parser.next() { Some((new_line, c)) => { match c { - '#' if new_line => { // don’t warn on titles + '#' if new_line => { + // don’t warn on titles parser.next_line(); - } + }, '`' => { if try!(check_block!(parser, '`', new_line)) { continue; } try!(parser.jump_to('`')); // not a code block, just inline code - } + }, '~' => { if try!(check_block!(parser, '~', new_line)) { continue; @@ -317,7 +315,7 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)] // ~ does not introduce inline code, but two of them introduce // strikethrough. Too bad for the consistency but we don't care about // strikethrough. - } + }, '[' => { // Check for a reference definition `[foo]:` at the beginning of a line let mut link = true; @@ -335,24 +333,24 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)] parser.advance_begin(); parser.link = link; - } + }, ']' if parser.link => { parser.link = false; match parser.peek() { Some('(') => { try!(parser.jump_to(')')); - } + }, Some('[') => { try!(parser.jump_to(']')); - } + }, Some(_) => continue, None => return Err(()), } - } + }, c if !is_path_char(c) => { parser.advance_begin(); - } + }, _ => { if let Some((_, c)) = parser.find(|&(_, c)| !is_path_char(c)) { parser.put_back(c); @@ -361,10 +359,10 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)] let (word, span) = parser.word(); check_word(cx, valid_idents, word, span); parser.advance_begin(); - } + }, } - } + }, None => break, } } @@ -386,8 +384,7 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span s }; - s.chars().all(char::is_alphanumeric) && - s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 && + s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 } diff --git a/clippy_lints/src/drop_ref.rs b/clippy_lints/src/drop_ref.rs index b369a3ae386e..106e43e1b6f5 100644 --- a/clippy_lints/src/drop_ref.rs +++ b/clippy_lints/src/drop_ref.rs @@ -35,11 +35,11 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprCall(ref path, ref args) = expr.node { - if let ExprPath(None, _) = path.node { - let def_id = cx.tcx.expect_def(path.id).def_id(); + if let ExprPath(ref qpath) = path.node { + let def_id = cx.tcx.tables().qpath_def(qpath, path.id).def_id(); if match_def_path(cx, def_id, &paths::DROP) { if args.len() != 1 { return; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index b251b02632fa..2fe53d8cacf4 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,5 +1,5 @@ use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr, walk_block}; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, NestedVisitorMap}; use rustc::lint::*; use syntax::codemap::Span; use utils::SpanlessEq; @@ -39,8 +39,8 @@ impl LintPass for HashMapLint { } } -impl LateLintPass for HashMapLint { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprIf(ref check, ref then_block, ref else_block) = expr.node { if let ExprUnary(UnOp::UnNot, ref check) = check.node { if let Some((ty, map, key)) = check_cond(cx, check) { @@ -78,7 +78,10 @@ impl LateLintPass for HashMapLint { } } -fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr) -> Option<(&'static str, &'b Expr, &'b Expr)> { +fn check_cond<'a, 'tcx, 'b>( + cx: &'a LateContext<'a, 'tcx>, + check: &'b Expr +) -> Option<(&'static str, &'b Expr, &'b Expr)> { if_let_chain! {[ let ExprMethodCall(ref name, _, ref params) = check.node, params.len() >= 2, @@ -111,8 +114,8 @@ struct InsertVisitor<'a, 'tcx: 'a, 'b> { sole_expr: bool, } -impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> { - fn visit_expr(&mut self, expr: &'v Expr) { +impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> { + fn visit_expr(&mut self, expr: &'tcx Expr) { if_let_chain! {[ let ExprMethodCall(ref name, _, ref params) = expr.node, params.len() == 3, @@ -144,4 +147,7 @@ impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> { walk_expr(self, expr); } } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 9188c421ccd4..f4181da3c2b7 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -36,9 +36,9 @@ impl LintPass for UnportableVariant { } } -impl LateLintPass for UnportableVariant { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { #[allow(cast_possible_truncation, cast_sign_loss)] - fn check_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemEnum(ref def, _) = item.node { for var in &def.variants { let variant = &var.node; diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 4641bb054313..0bd1740c5459 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -1,9 +1,7 @@ //! lint on `use`ing all variants of an enum use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::map::Node::NodeItem; -use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; +use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray}; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::span_lint; @@ -34,8 +32,8 @@ impl LintPass for EnumGlobUse { } } -impl LateLintPass for EnumGlobUse { - fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { + fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: NodeId) { // only check top level `use` statements for item in &m.item_ids { self.lint_item(cx, cx.krate.item(item.id)); @@ -48,24 +46,12 @@ impl EnumGlobUse { if item.vis == Visibility::Public { return; // re-exports are fine } - if let ItemUse(ref item_use) = item.node { - if let ViewPath_::ViewPathGlob(_) = item_use.node { - if let Some(def) = cx.tcx.def_map.borrow().get(&item.id) { - if let Some(node_id) = cx.tcx.map.as_local_node_id(def.full_def().def_id()) { - if let Some(NodeItem(it)) = cx.tcx.map.find(node_id) { - if let ItemEnum(..) = it.node { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } - } - } else { - let child = cx.sess().cstore.item_children(def.full_def().def_id()); - if let Some(child) = child.first() { - if let Def::Variant(..) = child.def { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } - } - } - } + if let ItemUse(ref path, UseKind::Glob) = item.node { + // FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;` + // extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an `Enum` + // if let Def::Enum(_) = path.def { + if path.segments.last().and_then(|seg| seg.name.as_str().chars().next()).map_or(false, char::is_uppercase) { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } } } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 74611d491c7f..e7b73809dff2 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -28,6 +28,27 @@ declare_lint! { "enums where all variants share a prefix/postfix" } +/// **What it does:** Detects enumeration variants that are prefixed or suffixed +/// by the same characters. +/// +/// **Why is this bad?** Enumeration variant names should specify their variant, +/// not repeat the enumeration name. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// enum Cake { +/// BlackForestCake, +/// HummingbirdCake, +/// } +/// ``` +declare_lint! { + pub PUB_ENUM_VARIANT_NAMES, + Allow, + "enums where all variants share a prefix/postfix" +} + /// **What it does:** Detects type names that are prefixed or suffixed by the /// containing module's name. /// @@ -49,10 +70,13 @@ declare_lint! { /// **What it does:** Checks for modules that have the same name as their parent module /// -/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and again `mod foo { .. }` in `foo.rs`. -/// The expectation is that items inside the inner `mod foo { .. }` are then available +/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and again `mod foo { .. +/// }` in `foo.rs`. +/// The expectation is that items inside the inner `mod foo { .. }` are then +/// available /// through `foo::x`, but they are only available through `foo::foo::x`. -/// If this is done on purpose, it would be better to choose a more representative module name. +/// If this is done on purpose, it would be better to choose a more +/// representative module name. /// /// **Known problems:** None. /// @@ -78,13 +102,16 @@ pub struct EnumVariantNames { impl EnumVariantNames { pub fn new(threshold: u64) -> EnumVariantNames { - EnumVariantNames { modules: Vec::new(), threshold: threshold } + EnumVariantNames { + modules: Vec::new(), + threshold: threshold, + } } } impl LintPass for EnumVariantNames { fn get_lints(&self) -> LintArray { - lint_array!(ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION) + lint_array!(ENUM_VARIANT_NAMES, PUB_ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION) } } @@ -108,18 +135,25 @@ fn partial_rmatch(post: &str, name: &str) -> usize { // FIXME: #600 #[allow(while_let_on_iterator)] -fn check_variant(cx: &EarlyContext, threshold: u64, def: &EnumDef, item_name: &str, - item_name_chars: usize, span: Span) { +fn check_variant( + cx: &EarlyContext, + threshold: u64, + def: &EnumDef, + item_name: &str, + item_name_chars: usize, + span: Span, + lint: &'static Lint +) { if (def.variants.len() as u64) < threshold { return; } for var in &def.variants { let name = var2str(var); if partial_match(item_name, &name) == item_name_chars { - span_lint(cx, ENUM_VARIANT_NAMES, var.span, "Variant name starts with the enum's name"); + span_lint(cx, lint, var.span, "Variant name starts with the enum's name"); } if partial_rmatch(item_name, &name) == item_name_chars { - span_lint(cx, ENUM_VARIANT_NAMES, var.span, "Variant name ends with the enum's name"); + span_lint(cx, lint, var.span, "Variant name ends with the enum's name"); } } let first = var2str(&def.variants[0]); @@ -154,7 +188,7 @@ fn check_variant(cx: &EarlyContext, threshold: u64, def: &EnumDef, item_name: &s (true, false) => ("post", post), }; span_help_and_lint(cx, - ENUM_VARIANT_NAMES, + lint, span, &format!("All variants have the same {}fix: `{}`", what, value), &format!("remove the {}fixes and use full paths to \ @@ -200,7 +234,10 @@ impl EarlyLintPass for EnumVariantNames { if !mod_camel.is_empty() { if mod_name == &item_name { if let ItemKind::Mod(..) = item.node { - span_lint(cx, MODULE_INCEPTION, item.span, "module has the same name as its containing module"); + span_lint(cx, + MODULE_INCEPTION, + item.span, + "module has the same name as its containing module"); } } if item.vis == Visibility::Public { @@ -218,7 +255,11 @@ impl EarlyLintPass for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.node { - check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span); + let lint = match item.vis { + Visibility::Public => PUB_ENUM_VARIANT_NAMES, + _ => ENUM_VARIANT_NAMES, + }; + check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint); } self.modules.push((item_name, item_camel)); } diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 7591e3dc076c..bfc16a504570 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -32,8 +32,8 @@ impl LintPass for EqOp { } } -impl LateLintPass for EqOp { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) { span_lint(cx, @@ -48,19 +48,7 @@ impl LateLintPass for EqOp { fn is_valid_operator(op: &BinOp) -> bool { match op.node { - BiSub | - BiDiv | - BiEq | - BiLt | - BiLe | - BiGt | - BiGe | - BiNe | - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr => true, + BiSub | BiDiv | BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true, _ => false, } } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 703e37e77b01..ee415b363824 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -46,7 +46,7 @@ fn is_non_trait_box(ty: ty::Ty) -> bool { } } -struct EscapeDelegate<'a, 'tcx: 'a+'gcx, 'gcx: 'a> { +struct EscapeDelegate<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> { tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, set: NodeSet, infcx: &'a InferCtxt<'a, 'gcx, 'gcx>, @@ -60,8 +60,16 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Expr, _: Span, id: NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + _: visit::FnKind<'tcx>, + decl: &'tcx FnDecl, + body: &'tcx Expr, + _: Span, + id: NodeId + ) { let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env); @@ -90,7 +98,7 @@ impl LateLintPass for Pass { } } -impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'gcx> { +impl<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'gcx> { fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { if let Categorization::Local(lid) = cmt.cat { if self.set.contains(&lid) { @@ -143,18 +151,26 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g } } - fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: &ty::Region, _: ty::BorrowKind, - loan_cause: LoanCause) { + fn borrow( + &mut self, + borrow_id: NodeId, + _: Span, + cmt: cmt<'tcx>, + _: &ty::Region, + _: ty::BorrowKind, + loan_cause: LoanCause + ) { use rustc::ty::adjustment::Adjust; if let Categorization::Local(lid) = cmt.cat { if self.set.contains(&lid) { - if let Some(&Adjust::DerefRef { autoderefs, .. }) = self.tcx - .tables - .borrow() - .adjustments - .get(&borrow_id) - .map(|a| &a.kind) { + if let Some(&Adjust::DerefRef { autoderefs, .. }) = + self.tcx + .tables + .borrow() + .adjustments + .get(&borrow_id) + .map(|a| &a.kind) { if LoanCause::AutoRef == loan_cause { // x.foo() if autoderefs == 0 { @@ -165,14 +181,15 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g } } else if LoanCause::AddrOf == loan_cause { // &x - if let Some(&Adjust::DerefRef { autoderefs, .. }) = self.tcx - .tables - .borrow() - .adjustments - .get(&self.tcx - .map - .get_parent_node(borrow_id)) - .map(|a| &a.kind) { + if let Some(&Adjust::DerefRef { autoderefs, .. }) = + self.tcx + .tables + .borrow() + .adjustments + .get(&self.tcx + .map + .get_parent_node(borrow_id)) + .map(|a| &a.kind) { if autoderefs <= 1 { // foo(&x) where no extra autoreffing is happening self.set.remove(&lid); @@ -190,7 +207,7 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {} } -impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> EscapeDelegate<'a, 'tcx, 'gcx> { +impl<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> EscapeDelegate<'a, 'tcx, 'gcx> { fn is_large_box(&self, ty: ty::Ty<'gcx>) -> bool { // Large types need to be boxed to avoid stack // overflows. diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index ee0767f57dfd..f25014b6805e 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -33,22 +33,23 @@ impl LintPass for EtaPass { } } -impl LateLintPass for EtaPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { match expr.node { ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => { for arg in args { check_closure(cx, arg) } - } + }, _ => (), } } } fn check_closure(cx: &LateContext, expr: &Expr) { - if let ExprClosure(_, ref decl, ref ex, _) = expr.node { + if let ExprClosure(_, ref decl, eid, _) = expr.node { + let ex = cx.tcx.map.expr(eid); if let ExprCall(ref caller, ref args) = ex.node { if args.len() != decl.inputs.len() { // Not the same number of arguments, there @@ -64,17 +65,16 @@ fn check_closure(cx: &LateContext, expr: &Expr) { // Is it an unsafe function? They don't implement the closure traits ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) => { - if fn_ty.unsafety == Unsafety::Unsafe || - fn_ty.sig.skip_binder().output.sty == ty::TyNever { + if fn_ty.unsafety == Unsafety::Unsafe || fn_ty.sig.skip_binder().output().sty == ty::TyNever { return; } - } + }, _ => (), } for (a1, a2) in decl.inputs.iter().zip(args) { - if let PatKind::Binding(_, ident, _) = a1.pat.node { + if let PatKind::Binding(_, _, ident, _) = a1.pat.node { // XXXManishearth Should I be checking the binding mode here? - if let ExprPath(None, ref p) = a2.node { + if let ExprPath(QPath::Resolved(None, ref p)) = a2.node { if p.segments.len() != 1 { // If it's a proper path, it can't be a local variable return; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index d3c06a581791..f83b3271d506 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,5 +1,5 @@ use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{Visitor, walk_expr}; +use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; use rustc::hir::*; use rustc::ty; use rustc::lint::*; @@ -56,34 +56,38 @@ impl LintPass for EvalOrderDependence { } } -impl LateLintPass for EvalOrderDependence { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { // Find a write to a local variable. match expr.node { - ExprAssign(ref lhs, _) | ExprAssignOp(_, ref lhs, _) => { - if let ExprPath(None, ref path) = lhs.node { - if path.segments.len() == 1 { - let var = cx.tcx.expect_def(lhs.id).def_id(); - let mut visitor = ReadVisitor { - cx: cx, - var: var, - write_expr: expr, - last_expr: expr, - }; - check_for_unsequenced_reads(&mut visitor); + ExprAssign(ref lhs, _) | + ExprAssignOp(_, ref lhs, _) => { + if let ExprPath(ref qpath) = lhs.node { + if let QPath::Resolved(_, ref path) = *qpath { + if path.segments.len() == 1 { + let var = cx.tcx.tables().qpath_def(qpath, lhs.id).def_id(); + let mut visitor = ReadVisitor { + cx: cx, + var: var, + write_expr: expr, + last_expr: expr, + }; + check_for_unsequenced_reads(&mut visitor); + } } } - } - _ => {} + }, + _ => {}, } } - fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { match stmt.node { - StmtExpr(ref e, _) | StmtSemi(ref e, _) => DivergenceVisitor(cx).maybe_walk_expr(e), + StmtExpr(ref e, _) | + StmtSemi(ref e, _) => DivergenceVisitor { cx: cx }.maybe_walk_expr(e), StmtDecl(ref d, _) => { if let DeclLocal(ref local) = d.node { if let Local { init: Some(ref e), .. } = **local { - DivergenceVisitor(cx).visit_expr(e); + DivergenceVisitor { cx: cx }.visit_expr(e); } } }, @@ -91,10 +95,12 @@ impl LateLintPass for EvalOrderDependence { } } -struct DivergenceVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); +struct DivergenceVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, +} impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { - fn maybe_walk_expr(&mut self, e: &Expr) { + fn maybe_walk_expr(&mut self, e: &'tcx Expr) { match e.node { ExprClosure(..) => {}, ExprMatch(ref e, ref arms, _) => { @@ -106,51 +112,52 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { // make sure top level arm expressions aren't linted self.maybe_walk_expr(&*arm.body); } - } + }, _ => walk_expr(self, e), } } fn report_diverging_sub_expr(&mut self, e: &Expr) { - span_lint( - self.0, - DIVERGING_SUB_EXPRESSION, - e.span, - "sub-expression diverges", - ); + span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } } -impl<'a, 'tcx, 'v> Visitor<'v> for DivergenceVisitor<'a, 'tcx> { - fn visit_expr(&mut self, e: &'v Expr) { +impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr) { match e.node { - ExprAgain(_) | - ExprBreak(_, _) | - ExprRet(_) => self.report_diverging_sub_expr(e), - ExprCall(ref func, _) => match self.0.tcx.tables().expr_ty(func).sty { - ty::TyFnDef(_, _, fn_ty) | - ty::TyFnPtr(fn_ty) => if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&fn_ty.sig).output.sty { - self.report_diverging_sub_expr(e); - }, - _ => {}, + ExprAgain(_) | ExprBreak(_, _) | ExprRet(_) => self.report_diverging_sub_expr(e), + ExprCall(ref func, _) => { + match self.cx.tcx.tables().expr_ty(func).sty { + ty::TyFnDef(_, _, fn_ty) | + ty::TyFnPtr(fn_ty) => { + if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty.sig).output().sty { + self.report_diverging_sub_expr(e); + } + }, + _ => {}, + } }, ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(e.id); - let borrowed_table = self.0.tcx.tables.borrow(); + let borrowed_table = self.cx.tcx.tables.borrow(); let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen."); let result_ty = method_type.ty.fn_ret(); - if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&result_ty).sty { + if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&result_ty).sty { self.report_diverging_sub_expr(e); } }, _ => { - // do not lint expressions referencing objects of type `!`, as that required a diverging expression to begin with + // do not lint expressions referencing objects of type `!`, as that required a diverging expression + // to begin with }, } self.maybe_walk_expr(e); } - fn visit_block(&mut self, _: &'v Block) { + fn visit_block(&mut self, _: &'tcx Block) { // don't continue over blocks, LateLintPass already does that } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } /// Walks up the AST from the the given write expression (`vis.write_expr`) @@ -188,7 +195,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor) { // We reached the top of the function, stop. break; }, - _ => { StopEarly::KeepGoing } + _ => StopEarly::KeepGoing, }; match stop_early { StopEarly::Stop => break, @@ -207,7 +214,7 @@ enum StopEarly { Stop, } -fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEarly { +fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly { if expr.id == vis.last_expr.id { return StopEarly::KeepGoing; } @@ -222,7 +229,7 @@ fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEar ExprRepeat(_, _) | ExprStruct(_, _, _) => { walk_expr(vis, expr); - } + }, ExprBinary(op, _, _) | ExprAssignOp(op, _, _) => { if op.node == BiAnd || op.node == BiOr { @@ -231,7 +238,7 @@ fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEar } else { walk_expr(vis, expr); } - } + }, ExprClosure(_, _, _, _) => { // Either // @@ -245,10 +252,10 @@ fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEar // // This is also the only place we need to stop early (grrr). return StopEarly::Stop; - } + }, // All other expressions either have only one child or strictly // sequence the evaluation order of their sub-expressions. - _ => {} + _ => {}, } vis.last_expr = expr; @@ -256,7 +263,7 @@ fn check_expr<'v, 't>(vis: & mut ReadVisitor<'v, 't>, expr: &'v Expr) -> StopEar StopEarly::KeepGoing } -fn check_stmt<'v, 't>(vis: &mut ReadVisitor<'v, 't>, stmt: &'v Stmt) -> StopEarly { +fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> StopEarly { match stmt.node { StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => check_expr(vis, expr), @@ -269,43 +276,45 @@ fn check_stmt<'v, 't>(vis: &mut ReadVisitor<'v, 't>, stmt: &'v Stmt) -> StopEarl }; local.and_then(|local| local.init.as_ref()) .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)) - } + }, } } /// A visitor that looks for reads from a variable. -struct ReadVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, +struct ReadVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, /// The id of the variable we're looking for. var: DefId, /// The expressions where the write to the variable occurred (for reporting /// in the lint). - write_expr: &'v Expr, + write_expr: &'tcx Expr, /// The last (highest in the AST) expression we've checked, so we know not /// to recheck it. - last_expr: &'v Expr, + last_expr: &'tcx Expr, } -impl<'v, 't> Visitor<'v> for ReadVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { +impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { if expr.id == self.last_expr.id { return; } match expr.node { - ExprPath(None, ref path) => { - if path.segments.len() == 1 && self.cx.tcx.expect_def(expr.id).def_id() == self.var { - if is_in_assignment_position(self.cx, expr) { - // This is a write, not a read. - } else { - span_note_and_lint( - self.cx, - EVAL_ORDER_DEPENDENCE, - expr.span, - "unsequenced read of a variable", - self.write_expr.span, - "whether read occurs before this write depends on evaluation order" - ); + ExprPath(ref qpath) => { + if let QPath::Resolved(None, ref path) = *qpath { + if path.segments.len() == 1 && self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id() == self.var { + if is_in_assignment_position(self.cx, expr) { + // This is a write, not a read. + } else { + span_note_and_lint( + self.cx, + EVAL_ORDER_DEPENDENCE, + expr.span, + "unsequenced read of a variable", + self.write_expr.span, + "whether read occurs before this write depends on evaluation order" + ); + } } } } @@ -332,6 +341,9 @@ impl<'v, 't> Visitor<'v> for ReadVisitor<'v, 't> { walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } /// Returns true if `expr` is the LHS of an assignment, like `expr = ...`. diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 5a2c5f5c852e..1894a12a6d3e 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -38,17 +38,16 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let Some(span) = is_expn_of(cx, expr.span, "format") { match expr.node { // `format!("{}", foo)` expansion ExprCall(ref fun, ref args) => { if_let_chain!{[ - let ExprPath(..) = fun.node, + let ExprPath(ref qpath) = fun.node, args.len() == 2, - let Some(fun) = resolve_node(cx, fun.id), - match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1), + match_def_path(cx, resolve_node(cx, qpath, fun.id).def_id(), &paths::FMT_ARGUMENTS_NEWV1), // ensure the format string is `"{..}"` with only one argument and no text check_static_str(cx, &args[0]), // ensure the format argument is `{}` ie. Display with no fancy option @@ -56,7 +55,7 @@ impl LateLintPass for Pass { ], { span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); }} - } + }, // `format!("foo")` expansion contains `match () { () => [], }` ExprMatch(ref matchee, _, _) => { if let ExprTup(ref tup) = matchee.node { @@ -64,7 +63,7 @@ impl LateLintPass for Pass { span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); } } - } + }, _ => (), } } @@ -73,8 +72,7 @@ impl LateLintPass for Pass { /// Returns the slice of format string parts in an `Arguments::new_v1` call. /// Public because it's shared with a lint in print.rs. -pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) - -> Option> { +pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) -> Option> { if_let_chain! {[ let ExprBlock(ref block) = expr.node, block.stmts.len() == 1, @@ -129,9 +127,8 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { exprs.len() == 1, let ExprCall(_, ref args) = exprs[0].node, args.len() == 2, - let ExprPath(None, _) = args[1].node, - let Some(fun) = resolve_node(cx, args[1].id), - match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD), + let ExprPath(ref qpath) = args[1].node, + match_def_path(cx, resolve_node(cx, qpath, args[1].id).def_id(), &paths::DISPLAY_FMT_METHOD), ], { let ty = walk_ptrs_ty(cx.tcx.tables().pat_ty(&pat[0])); diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index e9af1a011d98..6fdedaeed43b 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -62,7 +62,7 @@ impl EarlyLintPass for Formatting { (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => { check_consecutive_ifs(cx, first, second); - } + }, _ => (), } } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index c6f17b615b62..5ad676e57a08 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -68,8 +68,16 @@ impl LintPass for Functions { } } -impl LateLintPass for Functions { - fn check_fn(&mut self, cx: &LateContext, kind: intravisit::FnKind, decl: &hir::FnDecl, expr: &hir::Expr, span: Span, nodeid: ast::NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + kind: intravisit::FnKind<'tcx>, + decl: &'tcx hir::FnDecl, + expr: &'tcx hir::Expr, + span: Span, + nodeid: ast::NodeId + ) { use rustc::hir::map::Node::*; let is_impl = if let Some(NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { @@ -97,21 +105,22 @@ impl LateLintPass for Functions { self.check_raw_ptr(cx, unsafety, decl, expr, nodeid); } - fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { - if let hir::MethodTraitItem(ref sig, ref expr) = item.node { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { + if let hir::MethodTraitItem(ref sig, eid) = item.node { // don't lint extern functions decls, it's not their fault if sig.abi == Abi::Rust { self.check_arg_number(cx, &sig.decl, item.span); } - if let Some(ref expr) = *expr { + if let Some(eid) = eid { + let expr = cx.tcx.map.expr(eid); self.check_raw_ptr(cx, sig.unsafety, &sig.decl, expr, item.id); } } } } -impl Functions { +impl<'a, 'tcx> Functions { fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { let args = decl.inputs.len() as u64; if args > self.threshold { @@ -122,7 +131,14 @@ impl Functions { } } - fn check_raw_ptr(&self, cx: &LateContext, unsafety: hir::Unsafety, decl: &hir::FnDecl, expr: &hir::Expr, nodeid: ast::NodeId) { + fn check_raw_ptr( + &self, + cx: &LateContext<'a, 'tcx>, + unsafety: hir::Unsafety, + decl: &'tcx hir::FnDecl, + expr: &'tcx hir::Expr, + nodeid: ast::NodeId + ) { if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::>(); @@ -138,9 +154,9 @@ impl Functions { } } -fn raw_ptr_arg(cx: &LateContext, arg: &hir::Arg) -> Option { - if let (&hir::PatKind::Binding(_, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &arg.ty.node) { - cx.tcx.def_map.borrow().get(&arg.pat.id).map(|pr| pr.full_def().def_id()) +fn raw_ptr_arg(_cx: &LateContext, arg: &hir::Arg) -> Option { + if let (&hir::PatKind::Binding(_, def_id, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &arg.ty.node) { + Some(def_id) } else { None } @@ -151,8 +167,8 @@ struct DerefVisitor<'a, 'tcx: 'a> { ptrs: HashSet, } -impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'v hir::Expr) { +impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprCall(ref f, ref args) => { let ty = self.cx.tcx.tables().expr_ty(f); @@ -162,7 +178,7 @@ impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> { self.check_arg(arg); } } - } + }, hir::ExprMethodCall(_, _, ref args) => { let method_call = ty::MethodCall::expr(expr.id); let base_type = self.cx.tcx.tables.borrow().method_map[&method_call].ty; @@ -172,19 +188,23 @@ impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> { self.check_arg(arg); } } - } + }, hir::ExprUnary(hir::UnDeref, ref ptr) => self.check_arg(ptr), _ => (), } hir::intravisit::walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.cx.tcx.map) + } } impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> { fn check_arg(&self, ptr: &hir::Expr) { - if let Some(def) = self.cx.tcx.def_map.borrow().get(&ptr.id) { - if self.ptrs.contains(&def.full_def().def_id()) { + if let hir::ExprPath(ref qpath) = ptr.node { + let def = self.cx.tcx.tables().qpath_def(qpath, ptr.id); + if self.ptrs.contains(&def.def_id()) { span_lint(self.cx, NOT_UNSAFE_PTR_ARG_DEREF, ptr.span, diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 92901aa7855b..a10a9523ac1b 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -31,8 +31,8 @@ impl LintPass for IdentityOp { } } -impl LateLintPass for IdentityOp { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if in_macro(cx, e.span) { return; } @@ -41,17 +41,17 @@ impl LateLintPass for IdentityOp { BiAdd | BiBitOr | BiBitXor => { check(cx, left, 0, e.span, right.span); check(cx, right, 0, e.span, left.span); - } + }, BiShl | BiShr | BiSub => check(cx, right, 0, e.span, left.span), BiMul => { check(cx, left, 1, e.span, right.span); check(cx, right, 1, e.span, left.span); - } + }, BiDiv => check(cx, right, 1, e.span, left.span), BiBitAnd => { check(cx, left, -1, e.span, right.span); check(cx, right, -1, e.span, left.span); - } + }, _ => (), } } diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs index 25ff7244cf16..921cd7f8885e 100644 --- a/clippy_lints/src/if_let_redundant_pattern_matching.rs +++ b/clippy_lints/src/if_let_redundant_pattern_matching.rs @@ -42,16 +42,15 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if let ExprMatch(ref op, ref arms, MatchSource::IfLetDesugar{..}) = expr.node { + if let ExprMatch(ref op, ref arms, MatchSource::IfLetDesugar { .. }) = expr.node { if arms[0].pats.len() == 1 { let good_method = match arms[0].pats[0].node { - PatKind::TupleStruct(ref path, ref pats, _) if pats.len() == 1 && pats[0].node == PatKind::Wild => { - + PatKind::TupleStruct(ref path, ref pats, _) if pats.len() == 1 && pats[0].node == PatKind::Wild => { if match_path(path, &paths::RESULT_OK) { "is_ok()" } else if match_path(path, &paths::RESULT_ERR) { @@ -59,15 +58,13 @@ impl LateLintPass for Pass { } else if match_path(path, &paths::OPTION_SOME) { "is_some()" } else { - return + return; } - } + }, - PatKind::Path(_, ref path) if match_path(path, &paths::OPTION_NONE) => { - "is_none()" - } + PatKind::Path(ref path) if match_path(path, &paths::OPTION_NONE) => "is_none()", - _ => return + _ => return, }; span_lint_and_then(cx, @@ -75,15 +72,13 @@ impl LateLintPass for Pass { arms[0].pats[0].span, &format!("redundant pattern matching, consider using `{}`", good_method), |db| { - let span = Span { - lo: expr.span.lo, - hi: op.span.hi, - expn_id: expr.span.expn_id, - }; - db.span_suggestion(span, - "try this", - format!("if {}.{}", snippet(cx, op.span, "_"), good_method)); - }); + let span = Span { + lo: expr.span.lo, + hi: op.span.hi, + expn_id: expr.span.expn_id, + }; + db.span_suggestion(span, "try this", format!("if {}.{}", snippet(cx, op.span, "_"), good_method)); + }); } } diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 273c1bd0eb0a..72a3d485bd08 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -55,14 +55,14 @@ impl EarlyLintPass for IfNotElse { item.span, "Unnecessary boolean `not` operation", "remove the `!` and swap the blocks of the if/else"); - } + }, ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => { span_help_and_lint(cx, IF_NOT_ELSE, item.span, "Unnecessary `!=` operation", "change to `==` and swap the blocks of the if/else"); - } + }, _ => (), } } diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 78b43974364d..3b3cd423729b 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -47,9 +47,10 @@ impl EarlyLintPass for ItemsAfterStatements { } // skip initial items - let stmts = item.stmts.iter() - .map(|stmt| &stmt.node) - .skip_while(|s| matches!(**s, StmtKind::Item(..))); + let stmts = item.stmts + .iter() + .map(|stmt| &stmt.node) + .skip_while(|s| matches!(**s, StmtKind::Item(..))); // lint on all further items for stmt in stmts { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index be93699bae65..22835b488403 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -59,8 +59,8 @@ impl LintPass for LenZero { } } -impl LateLintPass for LenZero { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if in_macro(cx, item.span) { return; } @@ -72,7 +72,7 @@ impl LateLintPass for LenZero { } } - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if in_macro(cx, expr.span) { return; } @@ -107,8 +107,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, - &format!("trait `{}` has a `len` method but no `is_empty` method", - item.name)); + &format!("trait `{}` has a `len` method but no `is_empty` method", item.name)); } } } @@ -118,7 +117,8 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool { &*item.name.as_str() == name && if let AssociatedItemKind::Method { has_self } = item.kind { - has_self && { + has_self && + { let did = cx.tcx.map.local_def_id(item.id.node_id); let impl_ty = cx.tcx.item_type(did); impl_ty.fn_args().skip_binder().len() == 1 @@ -146,9 +146,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, - &format!("item `{}` has a public `len` method but {} `is_empty` method", - ty, - is_empty)); + &format!("item `{}` has a public `len` method but {} `is_empty` method", ty, is_empty)); } } } @@ -164,7 +162,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) | (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => { check_len_zero(cx, span, &method.node, args, lit, op) - } + }, _ => (), } } @@ -188,7 +186,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { if let ty::AssociatedKind::Method = item.kind { if &*item.name.as_str() == "is_empty" { let ty = cx.tcx.item_type(item.def_id).fn_sig().skip_binder(); - ty.inputs.len() == 1 + ty.inputs().len() == 1 } else { false } @@ -199,20 +197,18 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { /// Check the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext, id: DefId) -> bool { - cx.tcx.inherent_impls.borrow().get(&id).map_or(false, |impls| impls.iter().any(|imp| { - cx.tcx.associated_items(*imp).any(|item| { - is_is_empty(cx, &item) - }) - })) + cx.tcx.inherent_impls.borrow().get(&id).map_or(false, |impls| { + impls.iter().any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item))) + }) } let ty = &walk_ptrs_ty(cx.tcx.tables().expr_ty(expr)); match ty.sty { - ty::TyTrait(_) => { + ty::TyDynamic(..) => { cx.tcx - .associated_items(ty.ty_to_def_id().expect("trait impl not found")) - .any(|item| is_is_empty(cx, &item)) - } + .associated_items(ty.ty_to_def_id().expect("trait impl not found")) + .any(|item| is_is_empty(cx, &item)) + }, ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, id)), ty::TyAdt(id, _) => has_is_empty_impl(cx, id.did), ty::TyArray(..) | ty::TyStr => true, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 598f1b3a57ab..88d74b018863 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -57,27 +57,26 @@ impl LintPass for LetIfSeq { } } -impl LateLintPass for LetIfSeq { - fn check_block(&mut self, cx: &LateContext, block: &hir::Block) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq { + fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) { let mut it = block.stmts.iter().peekable(); while let Some(stmt) = it.next() { if_let_chain! {[ let Some(expr) = it.peek(), let hir::StmtDecl(ref decl, _) = stmt.node, let hir::DeclLocal(ref decl) = decl.node, - let hir::PatKind::Binding(mode, ref name, None) = decl.pat.node, - let Some(def) = cx.tcx.def_map.borrow().get(&decl.pat.id), + let hir::PatKind::Binding(mode, def_id, ref name, None) = decl.pat.node, let hir::StmtExpr(ref if_, _) = expr.node, let hir::ExprIf(ref cond, ref then, ref else_) = if_.node, - !used_in_expr(cx, def.full_def().def_id(), cond), - let Some(value) = check_assign(cx, def.full_def().def_id(), then), - !used_in_expr(cx, def.full_def().def_id(), value), + !used_in_expr(cx, def_id, cond), + let Some(value) = check_assign(cx, def_id, then), + !used_in_expr(cx, def_id, value), ], { let span = codemap::mk_sp(stmt.span.lo, if_.span.hi); let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { if let hir::ExprBlock(ref else_) = else_.node { - if let Some(default) = check_assign(cx, def.full_def().def_id(), else_) { + if let Some(default) = check_assign(cx, def_id, else_) { (else_.stmts.len() > 1, default) } else if let Some(ref default) = decl.init { (true, &**default) @@ -134,29 +133,34 @@ struct UsedVisitor<'a, 'tcx: 'a> { used: bool, } -impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UsedVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'v hir::Expr) { +impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if_let_chain! {[ - let hir::ExprPath(None, _) = expr.node, - let Some(def) = self.cx.tcx.def_map.borrow().get(&expr.id), - self.id == def.full_def().def_id(), + let hir::ExprPath(ref qpath) = expr.node, + self.id == self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id(), ], { self.used = true; return; }} hir::intravisit::walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> { + hir::intravisit::NestedVisitorMap::All(&self.cx.tcx.map) + } } -fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir::Block) -> Option<&'e hir::Expr> { +fn check_assign<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + decl: hir::def_id::DefId, + block: &'tcx hir::Block +) -> Option<&'tcx hir::Expr> { if_let_chain! {[ block.expr.is_none(), let Some(expr) = block.stmts.iter().last(), let hir::StmtSemi(ref expr, _) = expr.node, let hir::ExprAssign(ref var, ref value) = expr.node, - let hir::ExprPath(None, _) = var.node, - let Some(def) = cx.tcx.def_map.borrow().get(&var.id), - decl == def.full_def().def_id(), + let hir::ExprPath(ref qpath) = var.node, + decl == cx.tcx.tables().qpath_def(qpath, var.id).def_id(), ], { let mut v = UsedVisitor { cx: cx, @@ -178,7 +182,7 @@ fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir:: None } -fn used_in_expr(cx: &LateContext, id: hir::def_id::DefId, expr: &hir::Expr) -> bool { +fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: hir::def_id::DefId, expr: &'tcx hir::Expr) -> bool { let mut v = UsedVisitor { cx: cx, id: id, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a90f121fe79a..06aab286b2fe 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -9,6 +9,7 @@ #![feature(repeat_str)] #![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)] +#![allow(needless_lifetimes)] #[macro_use] extern crate syntax; @@ -115,6 +116,7 @@ pub mod precedence; pub mod print; pub mod ptr; pub mod ranges; +pub mod reference; pub mod regex; pub mod returns; pub mod serde; @@ -171,10 +173,22 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { }; let mut store = reg.sess.lint_store.borrow_mut(); - store.register_removed("unstable_as_slice", "`Vec::as_slice` has been stabilized in 1.7"); - store.register_removed("unstable_as_mut_slice", "`Vec::as_mut_slice` has been stabilized in 1.7"); - store.register_removed("str_to_string", "using `str::to_string` is common even today and specialization will likely happen soon"); - store.register_removed("string_to_string", "using `string::to_string` is common even today and specialization will likely happen soon"); + store.register_removed( + "unstable_as_slice", + "`Vec::as_slice` has been stabilized in 1.7", + ); + store.register_removed( + "unstable_as_mut_slice", + "`Vec::as_mut_slice` has been stabilized in 1.7", + ); + store.register_removed( + "str_to_string", + "using `str::to_string` is common even today and specialization will likely happen soon", + ); + store.register_removed( + "string_to_string", + "using `string::to_string` is common even today and specialization will likely happen soon", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` reg.register_late_lint_pass(box serde::Serde); @@ -227,7 +241,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box map_clone::Pass); reg.register_late_lint_pass(box temporary_assignment::Pass); reg.register_late_lint_pass(box transmute::Transmute); - reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold)); + reg.register_late_lint_pass( + box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold) + ); reg.register_late_lint_pass(box escape::Pass{too_large_for_stack: conf.too_large_for_stack}); reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box array_indexing::ArrayIndexing); @@ -256,7 +272,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents)); reg.register_late_lint_pass(box neg_multiply::NegMultiply); - reg.register_late_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); + reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); reg.register_late_lint_pass(box mem_forget::MemForget); reg.register_late_lint_pass(box arithmetic::Arithmetic::default()); reg.register_late_lint_pass(box assign_ops::AssignOps); @@ -266,6 +282,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box ok_if_let::Pass); reg.register_late_lint_pass(box if_let_redundant_pattern_matching::Pass); reg.register_late_lint_pass(box partialeq_ne_impl::Pass); + reg.register_early_lint_pass(box reference::Pass); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -277,6 +294,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_lint_group("clippy_pedantic", vec![ booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, + enum_variants::PUB_ENUM_VARIANT_NAMES, enum_variants::STUTTER, if_not_else::IF_NOT_ELSE, items_after_statements::ITEMS_AFTER_STATEMENTS, @@ -431,6 +449,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { ptr::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, ranges::RANGE_ZIP_WITH_LEN, + reference::DEREF_ADDROF, regex::INVALID_REGEX, regex::REGEX_MACRO, regex::TRIVIAL_REGEX, diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 710604b3a282..ba705a84089c 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -2,10 +2,10 @@ use reexport::*; use rustc::lint::*; use rustc::hir::def::Def; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; +use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics, NestedVisitorMap}; use std::collections::{HashSet, HashMap}; use syntax::codemap::Span; -use utils::{in_external_macro, span_lint}; +use utils::{in_external_macro, span_lint, last_path_segment}; /// **What it does:** Checks for lifetime annotations which can be removed by /// relying on lifetime elision. @@ -56,20 +56,20 @@ impl LintPass for LifetimePass { } } -impl LateLintPass for LifetimePass { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { check_fn_inner(cx, decl, generics, item.span); } } - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) { if let ImplItemKind::Method(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, &sig.generics, item.span); } } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, &sig.generics, item.span); } @@ -87,25 +87,25 @@ enum RefLt { fn bound_lifetimes(bound: &TyParamBound) -> HirVec<&Lifetime> { if let TraitTyParamBound(ref trait_ref, _) = *bound { trait_ref.trait_ref - .path - .segments - .last() - .expect("a path must have at least one segment") - .parameters - .lifetimes() + .path + .segments + .last() + .expect("a path must have at least one segment") + .parameters + .lifetimes() } else { HirVec::new() } } -fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &Generics, span: Span) { +fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, generics: &'tcx Generics, span: Span) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } let bounds_lts = generics.ty_params - .iter() - .flat_map(|typ| typ.bounds.iter().flat_map(bound_lifetimes)); + .iter() + .flat_map(|typ| typ.bounds.iter().flat_map(bound_lifetimes)); if could_use_elision(cx, decl, &generics.lifetimes, bounds_lts) { span_lint(cx, @@ -116,9 +116,12 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &Generics, span: Sp report_extra_lifetimes(cx, decl, generics); } -fn could_use_elision<'a, T: Iterator>(cx: &LateContext, func: &FnDecl, - named_lts: &[LifetimeDef], bounds_lts: T) - -> bool { +fn could_use_elision<'a, 'tcx: 'a, T: Iterator>( + cx: &LateContext<'a, 'tcx>, + func: &'tcx FnDecl, + named_lts: &'tcx [LifetimeDef], + bounds_lts: T +) -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT // * output references, exactly one input reference with same LT @@ -210,8 +213,8 @@ fn unique_lifetimes(lts: &[RefLt]) -> usize { } /// A visitor usable for `rustc_front::visit::walk_ty()`. -struct RefVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, +struct RefVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, lts: Vec, } @@ -239,56 +242,57 @@ impl<'v, 't> RefVisitor<'v, 't> { self.lts } - fn collect_anonymous_lifetimes(&mut self, path: &Path, ty: &Ty) { - let last_path_segment = path.segments.last().map(|s| &s.parameters); - if let Some(&AngleBracketedParameters(ref params)) = last_path_segment { + fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) { + let last_path_segment = &last_path_segment(qpath).parameters; + if let AngleBracketedParameters(ref params) = *last_path_segment { if params.lifetimes.is_empty() { - if let Some(def) = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()) { - match def { - Def::TyAlias(def_id) | - Def::Struct(def_id) => { - let generics = self.cx.tcx.item_generics(def_id); - for _ in generics.regions.as_slice() { - self.record(&None); - } + match self.cx.tcx.tables().qpath_def(qpath, ty.id) { + Def::TyAlias(def_id) | + Def::Struct(def_id) => { + let generics = self.cx.tcx.item_generics(def_id); + for _ in generics.regions.as_slice() { + self.record(&None); } - Def::Trait(def_id) => { - let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; - for _ in &trait_def.generics.regions { - self.record(&None); - } + }, + Def::Trait(def_id) => { + let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; + for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions { + self.record(&None); } - _ => (), - } + }, + _ => (), } } } } } -impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { +impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { self.record(&Some(*lifetime)); } - fn visit_ty(&mut self, ty: &'v Ty) { + fn visit_ty(&mut self, ty: &'tcx Ty) { match ty.node { TyRptr(None, _) => { self.record(&None); - } - TyPath(_, ref path) => { + }, + TyPath(ref path) => { self.collect_anonymous_lifetimes(path, ty); - } + }, _ => (), } walk_ty(self, ty); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } } /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to /// reason about elision. -fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { +fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool { for predicate in &where_clause.predicates { match *predicate { WherePredicate::RegionPredicate(..) => return true, @@ -312,47 +316,52 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { return true; } } - } + }, WherePredicate::EqPredicate(ref pred) => { let mut visitor = RefVisitor::new(cx); walk_ty(&mut visitor, &pred.ty); if !visitor.lts.is_empty() { return true; } - } + }, } } false } -struct LifetimeChecker(HashMap); +struct LifetimeChecker { + map: HashMap, +} -impl<'v> Visitor<'v> for LifetimeChecker { +impl<'tcx> Visitor<'tcx> for LifetimeChecker { // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { - self.0.remove(&lifetime.name); + fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { + self.map.remove(&lifetime.name); } - fn visit_lifetime_def(&mut self, _: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) { // don't actually visit `<'a>` or `<'a: 'b>` // we've already visited the `'a` declarations and // don't want to spuriously remove them // `'b` in `'a: 'b` is useless unless used elsewhere in // a non-lifetime bound } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } } -fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { +fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) { let hs = generics.lifetimes - .iter() - .map(|lt| (lt.lifetime.name, lt.lifetime.span)) - .collect(); - let mut checker = LifetimeChecker(hs); + .iter() + .map(|lt| (lt.lifetime.name, lt.lifetime.span)) + .collect(); + let mut checker = LifetimeChecker { map: hs }; walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); - for &v in checker.0.values() { + for &v in checker.map.values() { span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f5d9b91bb8c6..9a3defec72df 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2,7 +2,7 @@ use reexport::*; use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl, NestedVisitorMap}; use rustc::hir::map::Node::NodeBlock; use rustc::lint::*; use rustc::middle::const_val::ConstVal; @@ -14,9 +14,9 @@ use std::collections::HashMap; use syntax::ast; use utils::sugg; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, - in_external_macro, is_refutable, span_help_and_lint, is_integer_literal, - get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro, + is_refutable, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher, + walk_ptrs_ty, last_path_segment}; use utils::paths; /// **What it does:** Checks for looping over the range of `0..len` of some @@ -307,8 +307,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let Some((pat, arg, body)) = higher::for_loop(expr) { check_for_loop(cx, pat, arg, body, expr); } @@ -334,8 +334,7 @@ impl LateLintPass for Pass { match *source { MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { - if arms.len() == 2 && - arms[0].pats.len() == 1 && arms[0].guard.is_none() && + if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && arms[1].guard.is_none() && is_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { @@ -352,13 +351,13 @@ impl LateLintPass for Pass { expr.span, "this loop could be written as a `while let` loop", |db| { - let sug = format!("while let {} = {} {{ .. }}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, "..")); - db.span_suggestion(expr.span, "try", sug); - }); + let sug = format!("while let {} = {} {{ .. }}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, "..")); + db.span_suggestion(expr.span, "try", sug); + }); } - } + }, _ => (), } } @@ -366,33 +365,28 @@ impl LateLintPass for Pass { } if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { let pat = &arms[0].pats[0].node; - if let (&PatKind::TupleStruct(ref path, ref pat_args, _), + if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _), &ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) { let iter_expr = &method_args[0]; - if let Some(lhs_constructor) = path.segments.last() { - if &*method_name.node.as_str() == "next" && - match_trait_method(cx, match_expr, &paths::ITERATOR) && - &*lhs_constructor.name.as_str() == "Some" && - !is_refutable(cx, &pat_args[0]) && - !is_iterator_used_after_while_let(cx, iter_expr) { - let iterator = snippet(cx, method_args[0].span, "_"); - let loop_var = snippet(cx, pat_args[0].span, "_"); - span_lint_and_then(cx, - WHILE_LET_ON_ITERATOR, - expr.span, - "this loop could be written as a `for` loop", - |db| { - db.span_suggestion(expr.span, - "try", - format!("for {} in {} {{ .. }}", loop_var, iterator)); - }); - } + let lhs_constructor = last_path_segment(qpath); + if &*method_name.node.as_str() == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) && + &*lhs_constructor.name.as_str() == "Some" && !is_refutable(cx, &pat_args[0]) && + !is_iterator_used_after_while_let(cx, iter_expr) { + let iterator = snippet(cx, method_args[0].span, "_"); + let loop_var = snippet(cx, pat_args[0].span, "_"); + span_lint_and_then(cx, + WHILE_LET_ON_ITERATOR, + expr.span, + "this loop could be written as a `for` loop", + |db| { + db.span_suggestion(expr.span, "try", format!("for {} in {} {{ .. }}", loop_var, iterator)); + }); } } } } - fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { if args.len() == 1 && &*method.node.as_str() == "collect" && @@ -408,7 +402,13 @@ impl LateLintPass for Pass { } } -fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { +fn check_for_loop<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + pat: &'tcx Pat, + arg: &'tcx Expr, + body: &'tcx Expr, + expr: &'tcx Expr +) { check_for_loop_range(cx, pat, arg, body, expr); check_for_loop_reverse_range(cx, arg, expr); check_for_loop_arg(cx, pat, arg, expr); @@ -418,13 +418,19 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E /// Check for looping over a range and then indexing a sequence with it. /// The iteratee must be a range literal. -fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { +fn check_for_loop_range<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + pat: &'tcx Pat, + arg: &'tcx Expr, + body: &'tcx Expr, + expr: &'tcx Expr +) { if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::range(arg) { // the var must be a single name - if let PatKind::Binding(_, ref ident, _) = pat.node { + if let PatKind::Binding(_, def_id, ref ident, _) = pat.node { let mut visitor = VarVisitor { cx: cx, - var: cx.tcx.expect_def(pat.id).def_id(), + var: def_id, indexed: HashMap::new(), nonindex: false, }; @@ -433,9 +439,9 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { let (indexed, indexed_extent) = visitor.indexed - .into_iter() - .next() - .unwrap_or_else(|| unreachable!() /* len == 1 */); + .into_iter() + .next() + .unwrap_or_else(|| unreachable!() /* len == 1 */); // ensure that the indexed variable was declared before the loop, see #601 if let Some(indexed_extent) = indexed_extent { @@ -461,10 +467,8 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex ast::RangeLimits::Closed => { let end = sugg::Sugg::hir(cx, end, ""); format!(".take({})", end + sugg::ONE) - } - ast::RangeLimits::HalfOpen => { - format!(".take({})", snippet(cx, end.span, "..")) - } + }, + ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, end.span, "..")), } } } else { @@ -477,10 +481,10 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex expr.span, &format!("the loop variable `{}` is used to index `{}`", ident.node, indexed), |db| { - multispan_sugg(db, "consider using an iterator".to_string(), &[ - (pat.span, &format!("({}, )", ident.node)), - (arg.span, &format!("{}.iter().enumerate(){}{}", indexed, take, skip)), - ]); + multispan_sugg(db, + "consider using an iterator".to_string(), + &[(pat.span, &format!("({}, )", ident.node)), + (arg.span, &format!("{}.iter().enumerate(){}{}", indexed, take, skip))]); }); } else { let repl = if starts_at_zero && take.is_empty() { @@ -492,12 +496,13 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex span_lint_and_then(cx, NEEDLESS_RANGE_LOOP, expr.span, - &format!("the loop variable `{}` is only used to index `{}`.", ident.node, indexed), + &format!("the loop variable `{}` is only used to index `{}`.", + ident.node, + indexed), |db| { - multispan_sugg(db, "consider using an iterator".to_string(), &[ - (pat.span, ""), - (arg.span, &repl), - ]); + multispan_sugg(db, + "consider using an iterator".to_string(), + &[(pat.span, ""), (arg.span, &repl)]); }); } } @@ -510,7 +515,7 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { let ExprMethodCall(method, _, ref len_args) = expr.node, len_args.len() == 1, &*method.node.as_str() == "len", - let ExprPath(_, ref path) = len_args[0].node, + let ExprPath(QPath::Resolved(_, ref path)) = len_args[0].node, path.segments.len() == 1, &path.segments[0].name == var ], { @@ -533,7 +538,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { let (sup, eq) = match (start_idx, end_idx) { (ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => { (start_idx > end_idx, start_idx == end_idx) - } + }, _ => (false, false), }; @@ -551,15 +556,14 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { expr.span, "this range is empty so this for loop will never run", |db| { - db.span_suggestion(arg.span, - "consider using the following if \ - you are attempting to iterate \ - over this range in reverse", - format!("({end}{dots}{start}).rev()", - end=end_snippet, - dots=dots, - start=start_snippet)); - }); + db.span_suggestion(arg.span, + "consider using the following if you are attempting to iterate over this \ + range in reverse", + format!("({end}{dots}{start}).rev()", + end = end_snippet, + dots = dots, + start = start_snippet)); + }); } else if eq && limits != ast::RangeLimits::Closed { // if they are equal, it's also problematic - this loop // will never run. @@ -597,14 +601,14 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { method_name)); } } else if &*method_name.as_str() == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) { - let object = snippet(cx, args[0].span, "_"); - span_lint(cx, - EXPLICIT_INTO_ITER_LOOP, - expr.span, - &format!("it is more idiomatic to loop over `{}` instead of `{}.{}()`", - object, - object, - method_name)); + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, + EXPLICIT_INTO_ITER_LOOP, + expr.span, + &format!("it is more idiomatic to loop over `{}` instead of `{}.{}()`", + object, + object, + method_name)); } else if &*method_name.as_str() == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { span_lint(cx, @@ -647,7 +651,12 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { } } -fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { +fn check_for_loop_explicit_counter<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + arg: &'tcx Expr, + body: &'tcx Expr, + expr: &'tcx Expr +) { // Look for variables that are incremented once per loop iteration. let mut visitor = IncrementVisitor { cx: cx, @@ -692,14 +701,20 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex } /// Check for the `FOR_KV_MAP` lint. -fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { +fn check_for_loop_over_map_kv<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + pat: &'tcx Pat, + arg: &'tcx Expr, + body: &'tcx Expr, + expr: &'tcx Expr +) { let pat_span = pat.span; if let PatKind::Tuple(ref pat, _) = pat.node { if pat.len() == 2 { let (new_pat_span, kind) = match (&pat[0].node, &pat[1].node) { - (key, _) if pat_is_wild(key, body) => (pat[1].span, "value"), - (_, value) if pat_is_wild(value, body) => (pat[0].span, "key"), + (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value"), + (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key"), _ => return, }; @@ -717,10 +732,10 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex &format!("you seem to want to iterate on a map's {}s", kind), |db| { let map = sugg::Sugg::hir(cx, arg, "map"); - multispan_sugg(db, "use the corresponding method".into(), &[ - (pat_span, &snippet(cx, new_pat_span, kind)), - (arg_span, &format!("{}.{}s()", map.maybe_par(), kind)), - ]); + multispan_sugg(db, + "use the corresponding method".into(), + &[(pat_span, &snippet(cx, new_pat_span, kind)), + (arg_span, &format!("{}.{}s()", map.maybe_par(), kind))]); }); } } @@ -729,29 +744,31 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex } /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. -fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { +fn pat_is_wild<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, pat: &'tcx PatKind, body: &'tcx Expr) -> bool { match *pat { PatKind::Wild => true, - PatKind::Binding(_, ident, None) if ident.node.as_str().starts_with('_') => { + PatKind::Binding(_, _, ident, None) if ident.node.as_str().starts_with('_') => { let mut visitor = UsedVisitor { var: ident.node, used: false, + cx: cx, }; walk_expr(&mut visitor, body); !visitor.used - } + }, _ => false, } } -struct UsedVisitor { +struct UsedVisitor<'a, 'tcx: 'a> { var: ast::Name, // var to look for used: bool, // has the var been used otherwise? + cx: &'a LateContext<'a, 'tcx>, } -impl<'a> Visitor<'a> for UsedVisitor { - fn visit_expr(&mut self, expr: &Expr) { - if let ExprPath(None, ref path) = expr.node { +impl<'a, 'tcx: 'a> Visitor<'tcx> for UsedVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { + if let ExprPath(QPath::Resolved(None, ref path)) = expr.node { if path.segments.len() == 1 && path.segments[0].name == self.var { self.used = true; return; @@ -760,31 +777,35 @@ impl<'a> Visitor<'a> for UsedVisitor { walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } -struct VarVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference +struct VarVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, // context reference var: DefId, // var name to look for as index indexed: HashMap>, // indexed variables, the extent is None for global nonindex: bool, // has the var been used otherwise? } -impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { - if let ExprPath(None, ref path) = expr.node { - if path.segments.len() == 1 && self.cx.tcx.expect_def(expr.id).def_id() == self.var { - // we are referencing our variable! now check if it's as an index - if_let_chain! {[ - let Some(parexpr) = get_parent_expr(self.cx, expr), - let ExprIndex(ref seqexpr, _) = parexpr.node, - let ExprPath(None, ref seqvar) = seqexpr.node, - seqvar.segments.len() == 1 - ], { - let def_map = self.cx.tcx.def_map.borrow(); - if let Some(def) = def_map.get(&seqexpr.id) { - match def.base_def { +impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { + if let ExprPath(ref qpath) = expr.node { + if let QPath::Resolved(None, ref path) = *qpath { + if path.segments.len() == 1 && self.cx.tcx.tables().qpath_def(qpath, expr.id).def_id() == self.var { + // we are referencing our variable! now check if it's as an index + if_let_chain! {[ + let Some(parexpr) = get_parent_expr(self.cx, expr), + let ExprIndex(ref seqexpr, _) = parexpr.node, + let ExprPath(ref seqpath) = seqexpr.node, + let QPath::Resolved(None, ref seqvar) = *seqpath, + seqvar.segments.len() == 1 + ], { + let def = self.cx.tcx.tables().qpath_def(seqpath, seqexpr.id); + match def { Def::Local(..) | Def::Upvar(..) => { - let def_id = def.base_def.def_id(); + let def_id = def.def_id(); let node_id = self.cx.tcx.map.as_local_node_id(def_id).unwrap(); let extent = self.cx.tcx.region_maps.var_scope(node_id); @@ -797,18 +818,21 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { } _ => (), } - } - }} - // we are not indexing anything, record that - self.nonindex = true; - return; + }} + // we are not indexing anything, record that + self.nonindex = true; + return; + } } } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } -fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { +fn is_iterator_used_after_while_let<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, iter_expr: &'tcx Expr) -> bool { let def_id = match var_def_id(cx, iter_expr) { Some(id) => id, None => return false, @@ -826,16 +850,16 @@ fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool visitor.var_used_after_while_let } -struct VarUsedAfterLoopVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, +struct VarUsedAfterLoopVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, def_id: NodeId, iter_expr_id: NodeId, past_while_let: bool, var_used_after_while_let: bool, } -impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { +impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { if self.past_while_let { if Some(self.def_id) == var_def_id(self.cx, expr) { self.var_used_after_while_let = true; @@ -845,6 +869,9 @@ impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } @@ -900,10 +927,11 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> { Some(ref expr) if block.stmts.is_empty() => Some(expr), None if !block.stmts.is_empty() => { match block.stmts[0].node { - StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), + StmtExpr(ref expr, _) | + StmtSemi(ref expr, _) => Some(expr), StmtDecl(..) => None, } - } + }, _ => None, } } @@ -917,7 +945,7 @@ fn is_break_expr(expr: &Expr) -> bool { Some(subexpr) => is_break_expr(subexpr), None => false, } - } + }, _ => false, } } @@ -935,15 +963,15 @@ enum VarState { } /// Scan a for loop for variables that are incremented exactly once. -struct IncrementVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference +struct IncrementVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, // context reference states: HashMap, // incremented variables depth: u32, // depth of conditional expressions done: bool, } -impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { +impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { if self.done { return; } @@ -966,7 +994,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { *state = VarState::DontWarn; } } - } + }, ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, _ => (), @@ -984,12 +1012,15 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } /// Check whether a variable is initialized to zero at the start of a loop. -struct InitializeVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference - end_expr: &'v Expr, // the for loop. Stop scanning here. +struct InitializeVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, // context reference + end_expr: &'tcx Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, name: Option, @@ -997,12 +1028,12 @@ struct InitializeVisitor<'v, 't: 'v> { past_loop: bool, } -impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { - fn visit_decl(&mut self, decl: &'v Decl) { +impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { + fn visit_decl(&mut self, decl: &'tcx Decl) { // Look for declarations of the variable if let DeclLocal(ref local) = decl.node { if local.pat.id == self.var_id { - if let PatKind::Binding(_, ref ident, _) = local.pat.node { + if let PatKind::Binding(_, _, ref ident, _) = local.pat.node { self.name = Some(ident.node); self.state = if let Some(ref init) = local.init { @@ -1020,7 +1051,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { walk_decl(self, decl); } - fn visit_expr(&mut self, expr: &'v Expr) { + fn visit_expr(&mut self, expr: &'tcx Expr) { if self.state == VarState::DontWarn { return; } @@ -1040,14 +1071,14 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { match parent.node { ExprAssignOp(_, ref lhs, _) if lhs.id == expr.id => { self.state = VarState::DontWarn; - } + }, ExprAssign(ref lhs, ref rhs) if lhs.id == expr.id => { self.state = if is_integer_literal(rhs, 0) && self.depth == 0 { VarState::Warn } else { VarState::DontWarn } - } + }, ExprAddrOf(mutability, _) if mutability == MutMutable => self.state = VarState::DontWarn, _ => (), } @@ -1068,11 +1099,15 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } fn var_def_id(cx: &LateContext, expr: &Expr) -> Option { - if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { - if let Def::Local(def_id) = path_res.base_def { + if let ExprPath(ref qpath) = expr.node { + let path_res = cx.tcx.tables().qpath_def(qpath, expr.id); + if let Def::Local(def_id) = path_res { let node_id = cx.tcx.map.as_local_node_id(def_id).expect("That DefId should be valid"); return Some(node_id); } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 07bbc7038264..f04a4b32de2b 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -24,14 +24,14 @@ declare_lint! { #[derive(Copy, Clone)] pub struct Pass; -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { // call to .map() if let ExprMethodCall(name, _, ref args) = expr.node { if &*name.node.as_str() == "map" && args.len() == 2 { match args[1].node { - ExprClosure(_, ref decl, ref closure_expr, _) => { - let closure_expr = remove_blocks(closure_expr); + ExprClosure(_, ref decl, closure_eid, _) => { + let closure_expr = remove_blocks(cx.tcx.map.expr(closure_eid)); if_let_chain! {[ // nothing special in the argument, besides reference bindings // (e.g. .map(|&x| x) ) @@ -63,8 +63,8 @@ impl LateLintPass for Pass { } } }} - } - ExprPath(_, ref path) => { + }, + ExprPath(ref path) => { if match_path(path, &paths::CLONE) { let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); span_help_and_lint(cx, @@ -75,7 +75,7 @@ impl LateLintPass for Pass { type_name), &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); } - } + }, _ => (), } } @@ -85,13 +85,13 @@ impl LateLintPass for Pass { fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { match expr.node { - ExprPath(None, ref path) => { + ExprPath(QPath::Resolved(None, ref path)) => { let arg_segment = [PathSegment { name: id, parameters: PathParameters::none(), }]; !path.global && path.segments[..] == arg_segment - } + }, _ => false, } } @@ -108,7 +108,7 @@ fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static s fn get_arg_name(pat: &Pat) -> Option { match pat.node { - PatKind::Binding(_, name, None) => Some(name.node), + PatKind::Binding(_, _, name, None) => Some(name.node), PatKind::Ref(ref subpat, _) => get_arg_name(subpat), _ => None, } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 844715835b99..978e9f5a029f 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -125,12 +125,16 @@ pub struct MatchPass; impl LintPass for MatchPass { fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE, MATCH_OVERLAPPING_ARM) + lint_array!(SINGLE_MATCH, + MATCH_REF_PATS, + MATCH_BOOL, + SINGLE_MATCH_ELSE, + MATCH_OVERLAPPING_ARM) } } -impl LateLintPass for MatchPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if in_external_macro(cx, expr.span) { return; } @@ -192,7 +196,14 @@ fn check_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::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"), @@ -209,9 +220,9 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: return; } path.to_string() - } - PatKind::Binding(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), - PatKind::Path(None, ref path) => path.to_string(), + }, + PatKind::Binding(BindByValue(MutImmutable), _, ident, None) => ident.node.to_string(), + PatKind::Path(ref path) => path.to_string(), _ => return, }; @@ -272,16 +283,14 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, ".."), expr_block(cx, false_expr, None, ".."))) - } + }, (false, true) => { Some(format!("if {} {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, ".."))) - } + }, (true, false) => { let test = Sugg::hir(cx, ex, ".."); - Some(format!("if {} {}", - !test, - expr_block(cx, false_expr, None, ".."))) - } + Some(format!("if {} {}", !test, expr_block(cx, false_expr, None, ".."))) + }, (true, true) => None, }; @@ -291,7 +300,7 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } } - }); + }); } } @@ -333,8 +342,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match let ex = Sugg::hir(cx, ex, ".."); let template = match_template(expr.span, source, ex.deref()); db.span_suggestion(expr.span, - "instead of prefixing all patterns with `&`, you can \ - dereference the expression", + "instead of prefixing all patterns with `&`, you can dereference the expression", template); }); } @@ -346,11 +354,12 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec> { arms.iter() .flat_map(|arm| { if let Arm { ref pats, guard: None, .. } = *arm { - pats.iter() - } else { - [].iter() - }.filter_map(|pat| { - if_let_chain! {[ + pats.iter() + } else { + [].iter() + } + .filter_map(|pat| { + if_let_chain! {[ let PatKind::Range(ref lhs, ref rhs) = pat.node, let Ok(lhs) = eval_const_expr_partial(cx.tcx, lhs, ExprTypeChecked, None), let Ok(rhs) = eval_const_expr_partial(cx.tcx, rhs, ExprTypeChecked, None) @@ -358,15 +367,15 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec> { return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); }} - if_let_chain! {[ + if_let_chain! {[ let PatKind::Lit(ref value) = pat.node, let Ok(value) = eval_const_expr_partial(cx.tcx, value, ExprTypeChecked, None) ], { return Some(SpannedRange { span: pat.span, node: (value.clone(), value) }); }} - None - }) + None + }) }) .collect() } @@ -383,17 +392,17 @@ type TypedRanges = Vec>; /// `Uint` and `Int` probably don't make sense. fn type_ranges(ranges: &[SpannedRange]) -> TypedRanges { ranges.iter() - .filter_map(|range| { - if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node { - Some(SpannedRange { - span: range.span, - node: (start, end), - }) - } else { - None - } - }) - .collect() + .filter_map(|range| { + if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node { + Some(SpannedRange { + span: range.span, + node: (start, end), + }) + } else { + None + } + }) + .collect() } fn is_unit_expr(expr: &Expr) -> bool { @@ -406,15 +415,15 @@ fn is_unit_expr(expr: &Expr) -> bool { fn has_only_ref_pats(arms: &[Arm]) -> bool { let mapped = arms.iter() - .flat_map(|a| &a.pats) - .map(|p| { - match p.node { - PatKind::Ref(..) => Some(true), // &-patterns - PatKind::Wild => Some(false), // an "anything" wildcard is also fine - _ => None, // any other pattern is not fine - } - }) - .collect::>>(); + .flat_map(|a| &a.pats) + .map(|p| { + match p.node { + PatKind::Ref(..) => Some(true), // &-patterns + PatKind::Wild => Some(false), // an "anything" wildcard is also fine + _ => None, // any other pattern is not fine + } + }) + .collect::>>(); // look for Some(v) where there's at least one true element mapped.map_or(false, |v| v.iter().any(|el| *el)) } @@ -481,7 +490,7 @@ pub fn overlapping(ranges: &[SpannedRange]) -> Option<(&SpannedRange, & if ra.node != rb.node { return Some((ra, rb)); } - } + }, (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), _ => return Some((a.range(), b.range())), } diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 492962def6ab..55654a7de43b 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -27,11 +27,11 @@ impl LintPass for MemForget { } } -impl LateLintPass for MemForget { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprCall(ref path_expr, ref args) = e.node { - if let ExprPath(None, _) = path_expr.node { - let def_id = cx.tcx.expect_def(path_expr.id).def_id(); + if let ExprPath(ref qpath) = path_expr.node { + let def_id = cx.tcx.tables().qpath_def(qpath, path_expr.id).def_id(); if match_def_path(cx, def_id, &paths::MEM_FORGET) { let forgot_ty = cx.tcx.tables().expr_ty(&args[0]); diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 53c6eae91884..591b395fe709 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -3,14 +3,16 @@ use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::middle::const_qualif::ConstQualif; use rustc::ty; +use rustc::hir::def::Def; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; use std::borrow::Cow; use std::fmt; use syntax::codemap::Span; -use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path, - match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, - span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; +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}; use utils::paths; use utils::sugg; @@ -547,11 +549,11 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { #[allow(unused_attributes)] // ^ required because `cyclomatic_complexity` attribute shows up as unused #[cyclomatic_complexity = "30"] - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { if in_macro(cx, expr.span) { return; } @@ -614,20 +616,20 @@ impl LateLintPass for Pass { lint_single_char_pattern(cx, expr, &args[pos]); } } - } + }, _ => (), } - } + }, hir::ExprBinary(op, ref lhs, ref rhs) if op.node == hir::BiEq || op.node == hir::BiNe => { if !lint_chars_next(cx, expr, lhs, rhs, op.node == hir::BiEq) { lint_chars_next(cx, expr, rhs, lhs, op.node == hir::BiEq); } - } + }, _ => (), } } - fn check_impl_item(&mut self, cx: &LateContext, implitem: &hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, implitem: &'tcx hir::ImplItem) { if in_external_macro(cx, implitem.span) { return; } @@ -693,24 +695,27 @@ impl LateLintPass for Pass { /// Checks for the `OR_FUN_CALL` lint. fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir::Expr]) { /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. - fn check_unwrap_or_default(cx: &LateContext, name: &str, fun: &hir::Expr, self_expr: &hir::Expr, arg: &hir::Expr, - or_has_args: bool, span: Span) - -> bool { + fn check_unwrap_or_default( + cx: &LateContext, + name: &str, + fun: &hir::Expr, + self_expr: &hir::Expr, + arg: &hir::Expr, + or_has_args: bool, + span: Span + ) -> bool { if or_has_args { return false; } if name == "unwrap_or" { - if let hir::ExprPath(_, ref path) = fun.node { - let path: &str = &path.segments - .last() - .expect("A path must have at least one segment") - .name - .as_str(); + if let hir::ExprPath(ref qpath) = fun.node { + let path: &str = &*last_path_segment(qpath).name.as_str(); if ["default", "new"].contains(&path) { let arg_ty = cx.tcx.tables().expr_ty(arg); - let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { + let default_trait_id = if let Some(default_trait_id) = + get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { default_trait_id } else { return false; @@ -718,13 +723,14 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: if implements_trait(cx, arg_ty, default_trait_id, Vec::new()) { span_lint_and_then(cx, - OR_FUN_CALL, - span, - &format!("use of `{}` followed by a call to `{}`", name, path), - |db| { - db.span_suggestion(span, "try this", - format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); - }); + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a call to `{}`", name, path), + |db| { + db.span_suggestion(span, + "try this", + format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); + }); return true; } } @@ -735,8 +741,15 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: } /// Check for `*or(foo())`. - fn check_general_case(cx: &LateContext, name: &str, fun: &hir::Expr, self_expr: &hir::Expr, arg: &hir::Expr, or_has_args: bool, - span: Span) { + fn check_general_case( + cx: &LateContext, + name: &str, + fun: &hir::Expr, + self_expr: &hir::Expr, + arg: &hir::Expr, + or_has_args: bool, + span: Span + ) { // don't lint for constant values // FIXME: can we `expect` here instead of match? if let Some(qualif) = cx.tcx.const_qualif_map.borrow().get(&arg.id) { @@ -745,18 +758,16 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: } } // (path, fn_has_argument, methods, suffix) - let know_types: &[(&[_], _, &[_], _)] = &[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, - false, - &["map_or", "ok_or", "or", "unwrap_or"], - "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else")]; + let know_types: &[(&[_], _, &[_], _)] = + &[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else")]; let self_ty = cx.tcx.tables().expr_ty(self_expr); let (fn_has_arguments, poss, suffix) = if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)) { + know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)) { (fn_has_arguments, poss, suffix) } else { return; @@ -772,7 +783,11 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: (false, true) => snippet(cx, fun.span, ".."), }; - span_lint_and_then(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name), |db| { + span_lint_and_then(cx, + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a function call", name), + |db| { db.span_suggestion(span, "try this", format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); @@ -802,7 +817,9 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t "using `clone` on a double-reference; \ this will copy the reference instead of cloning the inner type", |db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { - db.span_suggestion(expr.span, "try dereferencing it", format!("({}).clone()", snip.deref())); + db.span_suggestion(expr.span, + "try dereferencing it", + format!("({}).clone()", snip.deref())); }); return; // don't report clone_on_copy } @@ -826,12 +843,14 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t fn lint_vec_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { let arg_ty = cx.tcx.tables().expr_ty(&args[1]); if let Some(slice) = derefs_to_slice(cx, &args[1], arg_ty) { - span_lint_and_then(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice", |db| { + span_lint_and_then(cx, + EXTEND_FROM_SLICE, + expr.span, + "use of `extend` to extend a Vec by a slice", + |db| { db.span_suggestion(expr.span, "try this", - format!("{}.extend_from_slice({})", - snippet(cx, args[0].span, "_"), - slice)); + format!("{}.extend_from_slice({})", snippet(cx, args[0].span, "_"), slice)); }); } } @@ -849,18 +868,14 @@ fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { return; }; - span_lint_and_then( - cx, - STRING_EXTEND_CHARS, - expr.span, - "calling `.extend(_.chars())`", - |db| { - db.span_suggestion(expr.span, "try this", - format!("{}.push_str({}{})", - snippet(cx, args[0].span, "_"), - ref_str, - snippet(cx, target.span, "_"))); - }); + span_lint_and_then(cx, STRING_EXTEND_CHARS, expr.span, "calling `.extend(_.chars())`", |db| { + db.span_suggestion(expr.span, + "try this", + format!("{}.push_str({}{})", + snippet(cx, args[0].span, "_"), + ref_str, + snippet(cx, target.span, "_"))); + }); } } @@ -877,8 +892,9 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr if_let_chain!{[ let hir::ExprCall(ref fun, ref args) = new.node, args.len() == 1, - let hir::ExprPath(None, ref path) = fun.node, - match_path(path, &paths::CSTRING_NEW), + let hir::ExprPath(ref path) = fun.node, + let Def::Method(did) = cx.tcx.tables().qpath_def(path, fun.id), + match_def_path(cx, did, &paths::CSTRING_NEW) ], { span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, "you are getting the inner pointer of a temporary `CString`", @@ -889,28 +905,24 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr }} } -fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool){ - let mut_str = if is_mut { "_mut" } else {""}; +fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) { + let mut_str = if is_mut { "_mut" } else { "" }; let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tcx.tables().expr_ty(&iter_args[0])).is_some() { "slice" - } - else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC) { + } else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC) { "Vec" - } - else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC_DEQUE) { + } else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC_DEQUE) { "VecDeque" - } - else { + } else { return; // caller is not a type that we want to lint }; - span_lint( - cx, - ITER_NTH, - expr.span, - &format!("called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable", - mut_str, caller_type) - ); + span_lint(cx, + ITER_NTH, + expr.span, + &format!("called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable", + mut_str, + caller_type)); } fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) { @@ -933,32 +945,29 @@ fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], i let mut_str = if is_mut { "_mut" } else { "" }; let borrow_str = if is_mut { "&mut " } else { "&" }; - span_lint_and_then( - cx, - GET_UNWRAP, - expr.span, - &format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", - mut_str, caller_type), - |db| { - db.span_suggestion( - expr.span, - "try this", - format!("{}{}[{}]", borrow_str, snippet(cx, get_args[0].span, "_"), - snippet(cx, get_args[1].span, "_")) - ); - } - ); + span_lint_and_then(cx, + GET_UNWRAP, + expr.span, + &format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", + mut_str, + caller_type), + |db| { + db.span_suggestion(expr.span, + "try this", + format!("{}{}[{}]", + borrow_str, + snippet(cx, get_args[0].span, "_"), + snippet(cx, get_args[1].span, "_"))); + }); } -fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr){ +fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr) { // lint if caller of skip is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - span_lint( - cx, - ITER_SKIP_NEXT, - expr.span, - "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`" - ); + span_lint(cx, + ITER_SKIP_NEXT, + expr.span, + "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`"); } } @@ -976,9 +985,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option Option None, } } @@ -1100,8 +1107,8 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &[hir:: fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &[hir::Expr]) { // lint if caller of `.filter().next()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` \ - instead."; + let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find(p)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { // add note if not multi-line @@ -1160,12 +1167,17 @@ fn lint_filter_map_flat_map(cx: &LateContext, expr: &hir::Expr, _filter_args: &[ } /// lint searching an Iterator followed by `is_some()` -fn lint_search_is_some(cx: &LateContext, expr: &hir::Expr, search_method: &str, search_args: &[hir::Expr], - is_some_args: &[hir::Expr]) { +fn lint_search_is_some( + cx: &LateContext, + expr: &hir::Expr, + search_method: &str, + search_args: &[hir::Expr], + is_some_args: &[hir::Expr] +) { // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { - let msg = format!("called `is_some()` after searching an `Iterator` with {}. This is more succinctly expressed \ - by calling `any()`.", + let msg = format!("called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ + expressed by calling `any()`.", search_method); let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { @@ -1188,8 +1200,9 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other: let Some(args) = method_chain_args(chain, &["chars", "next"]), let hir::ExprCall(ref fun, ref arg_char) = other.node, arg_char.len() == 1, - let hir::ExprPath(None, ref path) = fun.node, - path.segments.len() == 1 && &*path.segments[0].name.as_str() == "Some" + let hir::ExprPath(ref qpath) = fun.node, + let Some(segment) = single_segment_path(qpath), + &*segment.name.as_str() == "Some" ], { let self_ty = walk_ptrs_ty(cx.tcx.tables().expr_ty_adjusted(&args[0][0])); @@ -1227,8 +1240,8 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) arg.span, "single-character string constant used as pattern", |db| { - db.span_suggestion(expr.span, "try using a char instead:", hint); - }); + db.span_suggestion(expr.span, "try using a char instead:", hint); + }); } } } @@ -1408,7 +1421,7 @@ impl OutType { } fn is_bool(ty: &hir::Ty) -> bool { - if let hir::TyPath(None, ref p) = ty.node { + if let hir::TyPath(ref p) = ty.node { match_path(p, &["bool"]) } else { false diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 771408a9be63..d4198c97d13f 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -33,8 +33,8 @@ impl LintPass for MinMaxPass { } } -impl LateLintPass for MinMaxPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) { if let Some((inner_max, inner_c, _)) = min_max(cx, oe) { if outer_max == inner_max { @@ -46,7 +46,7 @@ impl LateLintPass for MinMaxPass { (MinMax::Min, Some(Ordering::Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); - } + }, } } } @@ -61,8 +61,8 @@ enum MinMax { fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &'a Expr)> { if let ExprCall(ref path, ref args) = expr.node { - if let ExprPath(None, _) = path.node { - let def_id = cx.tcx.expect_def(path.id).def_id(); + if let ExprPath(ref qpath) = path.node { + let def_id = cx.tcx.tables().qpath_def(qpath, path.id).def_id(); if match_def_path(cx, def_id, &paths::CMP_MIN) { fetch_const(args, MinMax::Min) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 6ad633489200..409a7de86f06 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -8,10 +8,8 @@ use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; use rustc_const_math::ConstFloat; use syntax::codemap::{Span, Spanned, ExpnFormat}; -use utils::{ - get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, - snippet, span_lint, span_lint_and_then, walk_ptrs_ty -}; +use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, snippet, + span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment}; use utils::sugg::Sugg; /// **What it does:** Checks for function arguments and let bindings denoted as `ref`. @@ -161,19 +159,32 @@ pub struct Pass; impl LintPass for Pass { fn get_lints(&self) -> LintArray { - lint_array!(TOPLEVEL_REF_ARG, CMP_NAN, FLOAT_CMP, CMP_OWNED, MODULO_ONE, REDUNDANT_PATTERN, + lint_array!(TOPLEVEL_REF_ARG, + CMP_NAN, + FLOAT_CMP, + CMP_OWNED, + MODULO_ONE, + REDUNDANT_PATTERN, USED_UNDERSCORE_BINDING) } } -impl LateLintPass for Pass { - fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Expr, _: Span, _: NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + k: FnKind<'tcx>, + decl: &'tcx FnDecl, + _: &'tcx Expr, + _: Span, + _: NodeId + ) { if let FnKind::Closure(_) = k { // Does not apply to closures return; } for arg in &decl.inputs { - if let PatKind::Binding(BindByRef(_), _, _) = arg.pat.node { + if let PatKind::Binding(BindByRef(_), _, _, _) = arg.pat.node { span_lint(cx, TOPLEVEL_REF_ARG, arg.pat.span, @@ -182,11 +193,11 @@ impl LateLintPass for Pass { } } - fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) { if_let_chain! {[ let StmtDecl(ref d, _) = s.node, let DeclLocal(ref l) = d.node, - let PatKind::Binding(BindByRef(mt), i, None) = l.pat.node, + let PatKind::Binding(BindByRef(mt), _, i, None) = l.pat.node, let Some(ref init) = l.init ], { let init = Sugg::hir(cx, init, ".."); @@ -216,14 +227,14 @@ impl LateLintPass for Pass { }} } - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if op.is_comparison() { - if let ExprPath(_, ref path) = left.node { + if let ExprPath(QPath::Resolved(_, ref path)) = left.node { check_nan(cx, path, expr.span); } - if let ExprPath(_, ref path) = right.node { + if let ExprPath(QPath::Resolved(_, ref path)) = right.node { check_nan(cx, path, expr.span); } check_to_owned(cx, left, right, true, cmp.span); @@ -236,23 +247,19 @@ impl LateLintPass for Pass { if let Some(name) = get_item_name(cx, expr) { let name = &*name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || - name.ends_with("_eq") { + name.ends_with("_eq") { return; } } - span_lint_and_then(cx, - FLOAT_CMP, - expr.span, - "strict comparison of f32 or f64", - |db| { - let lhs = Sugg::hir(cx, left, ".."); - let rhs = Sugg::hir(cx, right, ".."); + span_lint_and_then(cx, FLOAT_CMP, expr.span, "strict comparison of f32 or f64", |db| { + let lhs = Sugg::hir(cx, left, ".."); + let rhs = Sugg::hir(cx, right, ".."); - db.span_suggestion(expr.span, - "consider comparing them within some error", - format!("({}).abs() < error", lhs - rhs)); - db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available."); - }); + db.span_suggestion(expr.span, + "consider comparing them within some error", + format!("({}).abs() < error", lhs - rhs)); + db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available."); + }); } else if op == BiRem && is_integer_literal(right, 1) { span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } @@ -262,23 +269,19 @@ impl LateLintPass for Pass { return; } let binding = match expr.node { - ExprPath(_, ref path) => { - let binding = path.segments - .last() - .expect("path should always have at least one segment") - .name - .as_str(); + ExprPath(ref qpath) => { + let binding = last_path_segment(qpath).name.as_str(); if binding.starts_with('_') && !binding.starts_with("__") && &*binding != "_result" && // FIXME: #944 is_used(cx, expr) && // don't lint if the declaration is in a macro - non_macro_local(cx, &cx.tcx.expect_def(expr.id)) { + non_macro_local(cx, &cx.tcx.tables().qpath_def(qpath, expr.id)) { Some(binding) } else { None } - } + }, ExprField(_, spanned) => { let name = spanned.node.as_str(); if name.starts_with('_') && !name.starts_with("__") { @@ -286,7 +289,7 @@ impl LateLintPass for Pass { } else { None } - } + }, _ => None, }; if let Some(binding) = binding { @@ -294,19 +297,18 @@ impl LateLintPass for Pass { USED_UNDERSCORE_BINDING, expr.span, &format!("used binding `{}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used.", binding)); + underscore signals that a binding will not be used.", + binding)); } } - fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { - if let PatKind::Binding(_, ref ident, Some(ref right)) = pat.node { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { + if let PatKind::Binding(_, _, ref ident, Some(ref right)) = pat.node { if right.node == PatKind::Wild { span_lint(cx, REDUNDANT_PATTERN, pat.span, - &format!("the `{} @ _` pattern can be written as just `{}`", - ident.node, - ident.node)); + &format!("the `{} @ _` pattern can be written as just `{}`", ident.node, ident.node)); } } } @@ -343,9 +345,8 @@ fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { f64: ::std::f64::NEG_INFINITY, }; - val.try_cmp(zero) == Ok(Ordering::Equal) - || val.try_cmp(infinity) == Ok(Ordering::Equal) - || val.try_cmp(neg_infinity) == Ok(Ordering::Equal) + val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) || + val.try_cmp(neg_infinity) == Ok(Ordering::Equal) } else { false } @@ -364,9 +365,9 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S } else { return; } - } + }, ExprCall(ref path, ref v) if v.len() == 1 => { - if let ExprPath(None, ref path) = path.node { + if let ExprPath(ref path) = path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { (cx.tcx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) } else { @@ -375,7 +376,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S } else { return; } - } + }, _ => return, }; @@ -412,8 +413,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S } fn is_str_arg(cx: &LateContext, args: &[Expr]) -> bool { - args.len() == 1 && - matches!(walk_ptrs_ty(cx.tcx.tables().expr_ty(&args[0])).sty, ty::TyStr) + args.len() == 1 && matches!(walk_ptrs_ty(cx.tcx.tables().expr_ty(&args[0])).sty, ty::TyStr) } /// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea @@ -434,24 +434,21 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { /// `#[derive(...)`] or the like). fn in_attributes_expansion(cx: &LateContext, expr: &Expr) -> bool { cx.sess().codemap().with_expn_info(expr.span.expn_id, |info_opt| { - info_opt.map_or(false, |info| { - matches!(info.callee.format, ExpnFormat::MacroAttribute(_)) - }) + info_opt.map_or(false, |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_))) }) } /// 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, _, _) => { - let id = cx.tcx.map.as_local_node_id(id).expect("That DefId should be valid"); - - if let Some(span) = cx.tcx.map.opt_span(id) { + def::Def::Local(id) | + def::Def::Upvar(id, _, _) => { + if let Some(span) = cx.tcx.map.span_if_local(id) { !in_macro(cx, span) } else { true } - } + }, _ => false, } } diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index abb9d0fcb49a..e6f044ae9b6a 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -168,9 +168,14 @@ pub struct MiscEarly; impl LintPass for MiscEarly { fn get_lints(&self) -> LintArray { - lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL, - DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, - ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW) + lint_array!(UNNEEDED_FIELD_PATTERN, + DUPLICATE_UNDERSCORE_ARGUMENT, + REDUNDANT_CLOSURE_CALL, + DOUBLE_NEG, + MIXED_CASE_HEX_LITERALS, + UNSEPARATED_LITERAL_SUFFIX, + ZERO_PREFIXED_LITERAL, + BUILTIN_TYPE_SHADOW) } } @@ -272,14 +277,14 @@ impl EarlyLintPass for MiscEarly { expr.span, "Try not to call a closure in the expression where it is declared.", |db| { - if decl.inputs.is_empty() { - let hint = snippet(cx, block.span, "..").into_owned(); - db.span_suggestion(expr.span, "Try doing something like: ", hint); - } - }); + if decl.inputs.is_empty() { + let hint = snippet(cx, block.span, "..").into_owned(); + db.span_suggestion(expr.span, "Try doing something like: ", hint); + } + }); } } - } + }, ExprKind::Unary(UnOp::Neg, ref inner) => { if let ExprKind::Unary(UnOp::Neg, _) = inner.node { span_lint(cx, @@ -287,7 +292,7 @@ impl EarlyLintPass for MiscEarly { expr.span, "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op"); } - } + }, ExprKind::Lit(ref lit) => { if_let_chain! {[ let LitKind::Int(value, ..) = lit.node, @@ -328,8 +333,16 @@ impl EarlyLintPass for MiscEarly { lit.span, "this is a decimal constant", |db| { - db.span_suggestion(lit.span, "if you mean to use a decimal constant, remove the `0` to remove confusion:", src[1..].to_string()); - db.span_suggestion(lit.span, "if you mean to use an octal constant, use `0o`:", format!("0o{}", &src[1..])); + db.span_suggestion( + lit.span, + "if you mean to use a decimal constant, remove the `0` to remove confusion:", + src[1..].to_string(), + ); + db.span_suggestion( + lit.span, + "if you mean to use an octal constant, use `0o`:", + format!("0o{}", &src[1..]), + ); }); } }} @@ -351,8 +364,8 @@ impl EarlyLintPass for MiscEarly { prev = ch; } }} - } - _ => () + }, + _ => (), } } @@ -369,7 +382,12 @@ impl EarlyLintPass for MiscEarly { let ExprKind::Path(_, ref path) = closure.node ], { if sp_ident.node == (&path.segments[0]).identifier { - span_lint(cx, REDUNDANT_CLOSURE_CALL, second.span, "Closure called just once immediately after it was declared"); + span_lint( + cx, + REDUNDANT_CLOSURE_CALL, + second.span, + "Closure called just once immediately after it was declared", + ); } }} } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 7ca00500475f..70696ea3908b 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -1,21 +1,24 @@ -/* This file incorporates work covered by the following copyright and - * permission notice: - * Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT - * file at the top-level directory of this distribution and at - * http://rust-lang.org/COPYRIGHT. - * - * Licensed under the Apache License, Version 2.0 or the MIT license - * , at your - * option. This file may not be copied, modified, or distributed - * except according to those terms. - */ +// This file incorporates work covered by the following copyright and +// permission notice: +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// -/* Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s - * [`missing_doc`]. - * - * [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 - */ +// Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s +// [`missing_doc`]. +// +// [`missing_doc`]: +// https://github. +// com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin. +// rs#L246 +// use rustc::hir; use rustc::lint::*; @@ -51,20 +54,14 @@ impl ::std::default::Default for MissingDoc { impl MissingDoc { pub fn new() -> MissingDoc { - MissingDoc { - doc_hidden_stack: vec![false], - } + MissingDoc { doc_hidden_stack: vec![false] } } fn doc_hidden(&self) -> bool { *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") } - fn check_missing_docs_attrs(&self, - cx: &LateContext, - attrs: &[ast::Attribute], - sp: Span, - desc: &'static str) { + fn check_missing_docs_attrs(&self, cx: &LateContext, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { // If we're building a test harness, then warning about // documentation is probably not really relevant right now. if cx.sess().opts.test { @@ -82,7 +79,8 @@ impl MissingDoc { let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); if !has_doc { - cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, sp, + cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, + sp, &format!("missing documentation for {}", desc)); } } @@ -94,10 +92,12 @@ impl LintPass for MissingDoc { } } -impl LateLintPass for MissingDoc { - fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { - let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name("doc") && match attr.meta_item_list() { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { + fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) { + let doc_hidden = self.doc_hidden() || + attrs.iter().any(|attr| { + attr.check_name("doc") && + match attr.meta_item_list() { None => false, Some(l) => attr::list_contains_name(&l[..], "hidden"), } @@ -105,15 +105,15 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { + fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { self.check_missing_docs_attrs(cx, &krate.attrs, krate.span, "crate"); } - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let desc = match it.node { hir::ItemConst(..) => "a constant", hir::ItemEnum(..) => "an enum", @@ -134,7 +134,7 @@ impl LateLintPass for MissingDoc { self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc); } - fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir::TraitItem) { let desc = match trait_item.node { hir::ConstTraitItem(..) => "an associated constant", hir::MethodTraitItem(..) => "a trait method", @@ -144,16 +144,16 @@ impl LateLintPass for MissingDoc { self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, desc); } - fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) { // If the method is an impl for a trait, don't doc. let def_id = cx.tcx.map.local_def_id(impl_item.id); match cx.tcx.associated_item(def_id).container { ty::TraitContainer(_) => return, ty::ImplContainer(cid) => { if cx.tcx.impl_trait_ref(cid).is_some() { - return + return; } - } + }, } let desc = match impl_item.node { @@ -164,13 +164,13 @@ impl LateLintPass for MissingDoc { self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc); } - fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { + fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, sf: &'tcx hir::StructField) { if !sf.is_positional() { self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a struct field"); } } - fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { + fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, v: &'tcx hir::Variant, _: &hir::Generics) { self.check_missing_docs_attrs(cx, &v.node.attrs, v.span, "a variant"); } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index fe430a539a0f..7d4326828cb1 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -31,12 +31,12 @@ impl LintPass for MutMut { } } -impl LateLintPass for MutMut { - fn check_block(&mut self, cx: &LateContext, block: &hir::Block) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut { + fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) { intravisit::walk_block(&mut MutVisitor { cx: cx }, block); } - fn check_ty(&mut self, cx: &LateContext, ty: &hir::Ty) { + fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &'tcx hir::Ty) { use rustc::hir::intravisit::Visitor; MutVisitor { cx: cx }.visit_ty(ty); @@ -47,8 +47,8 @@ pub struct MutVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, } -impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'v hir::Expr) { +impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if in_external_macro(self.cx, expr.span) { return; } @@ -64,7 +64,10 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> { intravisit::walk_expr(self, body); } else if let hir::ExprAddrOf(hir::MutMutable, ref e) = expr.node { if let hir::ExprAddrOf(hir::MutMutable, _) = e.node { - span_lint(self.cx, MUT_MUT, expr.span, "generally you want to avoid `&mut &mut _` if possible"); + span_lint(self.cx, + MUT_MUT, + expr.span, + "generally you want to avoid `&mut &mut _` if possible"); } else if let TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tcx.tables().expr_ty(e).sty { span_lint(self.cx, MUT_MUT, @@ -74,14 +77,20 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: &hir::Ty) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyRptr(_, hir::MutTy { ty: ref pty, mutbl: hir::MutMutable }) = ty.node { if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node { - span_lint(self.cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); + span_lint(self.cx, + MUT_MUT, + ty.span, + "generally you want to avoid `&mut &mut _` if possible"); } } intravisit::walk_ty(self, ty); } + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.cx.tcx.map) + } } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index b2cdb2cb49b4..7e7733bed80c 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -32,25 +32,24 @@ impl LintPass for UnnecessaryMutPassed { } } -impl LateLintPass for UnnecessaryMutPassed { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { let borrowed_table = cx.tcx.tables.borrow(); match e.node { ExprCall(ref fn_expr, ref arguments) => { 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 { + .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, &path.to_string()); } - } + }, 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()) - } + }, _ => (), } } @@ -60,7 +59,7 @@ fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS, match type_definition.sty { TypeVariants::TyFnDef(_, _, fn_type) | TypeVariants::TyFnPtr(fn_type) => { - let parameters = &fn_type.sig.skip_binder().inputs; + let parameters = fn_type.sig.skip_binder().inputs(); for (argument, parameter) in arguments.iter().zip(parameters.iter()) { match parameter.sty { TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) | @@ -71,11 +70,11 @@ fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS, argument.span, &format!("The function/method \"{}\" doesn't need a mutable reference", name)); } - } + }, _ => (), } } - } + }, _ => (), } } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index bdf0ad2af98b..8d927110b9d2 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -54,8 +54,8 @@ impl LintPass for MutexAtomic { pub struct MutexAtomic; -impl LateLintPass for MutexAtomic { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { let ty = cx.tcx.tables().expr_ty(expr); if let ty::TyAdt(_, subst) = ty.sty { if match_type(cx, ty, &paths::MUTEX) { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 64f0af90aa81..5eae3034aff3 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -56,17 +56,13 @@ impl LintPass for NeedlessBool { } } -impl LateLintPass for NeedlessBool { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { use self::Expression::*; if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { let reduce = |ret, not| { let snip = Sugg::hir(cx, pred, ""); - let snip = if not { - !snip - } else { - snip - }; + let snip = if not { !snip } else { snip }; let hint = if ret { format!("return {}", snip) @@ -79,8 +75,8 @@ impl LateLintPass for NeedlessBool { e.span, "this if-then-else expression returns a bool literal", |db| { - db.span_suggestion(e.span, "you can reduce it to", hint); - }); + db.span_suggestion(e.span, "you can reduce it to", hint); + }); }; match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (RetBool(true), RetBool(true)) | @@ -89,14 +85,14 @@ impl LateLintPass for NeedlessBool { NEEDLESS_BOOL, e.span, "this if-then-else expression will always return true"); - } + }, (RetBool(false), RetBool(false)) | (Bool(false), Bool(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, "this if-then-else expression will always return false"); - } + }, (RetBool(true), RetBool(false)) => reduce(true, false), (Bool(true), Bool(false)) => reduce(false, false), (RetBool(false), RetBool(true)) => reduce(true, true), @@ -116,8 +112,8 @@ impl LintPass for BoolComparison { } } -impl LateLintPass for BoolComparison { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { use self::Expression::*; if let ExprBinary(Spanned { node: BiEq, .. }, ref left_side, ref right_side) = e.node { match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { @@ -128,9 +124,9 @@ impl LateLintPass for BoolComparison { e.span, "equality checks against true are unnecessary", |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", hint); - }); - } + db.span_suggestion(e.span, "try simplifying it as shown:", hint); + }); + }, (Other, Bool(true)) => { let hint = snippet(cx, left_side.span, "..").into_owned(); span_lint_and_then(cx, @@ -138,9 +134,9 @@ impl LateLintPass for BoolComparison { e.span, "equality checks against true are unnecessary", |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", hint); - }); - } + db.span_suggestion(e.span, "try simplifying it as shown:", hint); + }); + }, (Bool(false), Other) => { let hint = Sugg::hir(cx, right_side, ".."); span_lint_and_then(cx, @@ -148,9 +144,9 @@ impl LateLintPass for BoolComparison { e.span, "equality checks against false can be replaced by a negation", |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); - }); - } + db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); + }); + }, (Other, Bool(false)) => { let hint = Sugg::hir(cx, left_side, ".."); span_lint_and_then(cx, @@ -158,9 +154,9 @@ impl LateLintPass for BoolComparison { e.span, "equality checks against false can be replaced by a negation", |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); - }); - } + db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); + }); + }, _ => (), } } @@ -186,7 +182,7 @@ fn fetch_bool_block(block: &Block) -> Expression { } else { Expression::Other } - } + }, _ => Expression::Other, } } @@ -200,13 +196,13 @@ fn fetch_bool_expr(expr: &Expr) -> Expression { } else { Expression::Other } - } + }, ExprRet(Some(ref expr)) => { match fetch_bool_expr(expr) { Expression::Bool(value) => Expression::RetBool(value), _ => Expression::Other, } - } + }, _ => Expression::Other, } } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index b2199c226e96..f05fdaab1764 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -34,14 +34,15 @@ impl LintPass for NeedlessBorrow { } } -impl LateLintPass for NeedlessBorrow { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if in_macro(cx, e.span) { return; } if let ExprAddrOf(MutImmutable, ref inner) = e.node { if let ty::TyRef(..) = cx.tcx.tables().expr_ty(inner).sty { - if let Some(&ty::adjustment::Adjust::DerefRef { autoderefs, autoref, .. }) = cx.tcx.tables.borrow().adjustments.get(&e.id).map(|a| &a.kind) { + if let Some(&ty::adjustment::Adjust::DerefRef { autoderefs, autoref, .. }) = + cx.tcx.tables.borrow().adjustments.get(&e.id).map(|a| &a.kind) { if autoderefs > 1 && autoref.is_some() { span_lint(cx, NEEDLESS_BORROW, @@ -53,18 +54,15 @@ impl LateLintPass for NeedlessBorrow { } } } - fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { if in_macro(cx, pat.span) { return; } - if let PatKind::Binding(BindingMode::BindByRef(MutImmutable), _, _) = pat.node { + if let PatKind::Binding(BindingMode::BindByRef(MutImmutable), _, _, _) = pat.node { if let ty::TyRef(_, ref tam) = cx.tcx.tables().pat_ty(pat).sty { if tam.mutbl == MutImmutable { if let ty::TyRef(..) = tam.ty.sty { - span_lint(cx, - NEEDLESS_BORROW, - pat.span, - "this pattern creates a reference to a reference") + span_lint(cx, NEEDLESS_BORROW, pat.span, "this pattern creates a reference to a reference") } } } diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index cdd266ec2e87..de6277aa0ee5 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -30,8 +30,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprStruct(_, ref fields, Some(ref base)) = expr.node { let ty = cx.tcx.tables().expr_ty(expr); if let TyAdt(def, _) = ty.sty { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 5ca6172b6bcc..05a6a92c9e9d 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -31,8 +31,8 @@ impl LintPass for NegMultiply { } #[allow(match_same_arms)] -impl LateLintPass for NegMultiply { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprBinary(Spanned { node: BiMul, .. }, ref l, ref r) = e.node { match (&l.node, &r.node) { (&ExprUnary(..), &ExprUnary(..)) => (), diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 92d78e875dc1..9c7b132dd3d6 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -89,8 +89,16 @@ impl LintPass for NewWithoutDefault { } } -impl LateLintPass for NewWithoutDefault { - fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Expr, span: Span, id: ast::NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + span: Span, + id: ast::NodeId + ) { if in_external_macro(cx, span) { return; } @@ -153,7 +161,7 @@ fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_ } } true - } + }, _ => false, } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 973daa696b64..a87c9d0f7365 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,5 +1,5 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::hir::def::{Def, PathResolution}; +use rustc::hir::def::Def; use rustc::hir::{Expr, Expr_, Stmt, StmtSemi, BlockCheckMode, UnsafeSource}; use utils::{in_macro, span_lint, snippet_opt, span_lint_and_then}; use std::ops::Deref; @@ -66,17 +66,21 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { Some(ref base) => has_no_effect(cx, base), None => true, } - } + }, Expr_::ExprCall(ref callee, ref args) => { - let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); - match def { - Some(Def::Struct(..)) | - Some(Def::Variant(..)) | - Some(Def::StructCtor(..)) | - Some(Def::VariantCtor(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), - _ => false, + if let Expr_::ExprPath(ref qpath) = callee.node { + let def = cx.tcx.tables().qpath_def(qpath, callee.id); + match def { + Def::Struct(..) | + Def::Variant(..) | + Def::StructCtor(..) | + Def::VariantCtor(..) => args.iter().all(|arg| has_no_effect(cx, arg)), + _ => false, + } + } else { + false } - } + }, Expr_::ExprBlock(ref block) => { block.stmts.is_empty() && if let Some(ref expr) = block.expr { @@ -84,7 +88,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { } else { false } - } + }, _ => false, } } @@ -98,8 +102,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if has_no_effect(cx, expr) { span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect"); @@ -144,16 +148,21 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option reduce_expression(cx, inner).or_else(|| Some(vec![inner])), Expr_::ExprStruct(_, ref fields, ref base) => { Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect()) - } + }, Expr_::ExprCall(ref callee, ref args) => { - match cx.tcx.def_map.borrow().get(&callee.id).map(PathResolution::full_def) { - Some(Def::Struct(..)) | - Some(Def::Variant(..)) | - Some(Def::StructCtor(..)) | - Some(Def::VariantCtor(..)) => Some(args.iter().collect()), - _ => None, + if let Expr_::ExprPath(ref qpath) = callee.node { + let def = cx.tcx.tables().qpath_def(qpath, callee.id); + match def { + Def::Struct(..) | + Def::Variant(..) | + Def::StructCtor(..) | + Def::VariantCtor(..) => Some(args.iter().collect()), + _ => None, + } + } else { + None } - } + }, Expr_::ExprBlock(ref block) => { if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| { @@ -167,7 +176,7 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option None, } } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b5b901ccf847..a195673a53bc 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -59,9 +59,9 @@ struct ExistingName { whitelist: &'static [&'static str], } -struct SimilarNamesLocalVisitor<'a, 'b: 'a> { +struct SimilarNamesLocalVisitor<'a, 'tcx: 'a> { names: Vec, - cx: &'a EarlyContext<'b>, + cx: &'a EarlyContext<'tcx>, lint: &'a NonExpressiveNames, single_char_names: Vec, } @@ -76,10 +76,10 @@ const WHITELIST: &'static [&'static [&'static str]] = &[ &["set", "get"], ]; -struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); +struct SimilarNamesNameVisitor<'a: 'b, 'tcx: 'a, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>); -impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> { - fn visit_pat(&mut self, pat: &Pat) { +impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { + fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.node { PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), PatKind::Struct(_, ref fields, _) => { @@ -88,7 +88,7 @@ impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> { self.visit_pat(&field.node.pat); } } - } + }, _ => walk_pat(self, pat), } } @@ -120,7 +120,7 @@ fn whitelisted(interned_name: &str, list: &[&str]) -> bool { false } -impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { +impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { fn check_short_name(&mut self, c: char, span: Span) { // make sure we ignore shadowing if self.0.single_char_names.contains(&c) { @@ -210,8 +210,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { diag.span_help(span, &format!("separate the discriminating character by an \ underscore like: `{}_{}`", - &interned_name[..split], - &interned_name[split..])); + &interned_name[..split], + &interned_name[split..])); } }); return; @@ -236,20 +236,22 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { } } -impl<'a, 'b> Visitor for SimilarNamesLocalVisitor<'a, 'b> { - fn visit_local(&mut self, local: &Local) { +impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { + fn visit_local(&mut self, local: &'tcx Local) { if let Some(ref init) = local.init { self.apply(|this| walk_expr(this, &**init)); } - // add the pattern after the expression because the bindings aren't available yet in the init expression + // add the pattern after the expression because the bindings aren't available yet in the init + // expression SimilarNamesNameVisitor(self).visit_pat(&*local.pat); } - fn visit_block(&mut self, blk: &Block) { + fn visit_block(&mut self, blk: &'tcx Block) { self.apply(|this| walk_block(this, blk)); } - fn visit_arm(&mut self, arm: &Arm) { + fn visit_arm(&mut self, arm: &'tcx Arm) { self.apply(|this| { - // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier + // just go through the first pattern, as either all patterns + // bind the same bindings or rustc would have errored much earlier SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); this.apply(|this| walk_expr(this, &arm.body)); }); diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index 1fdfe43b6845..65b13688ff62 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -15,7 +15,7 @@ use utils::{paths, method_chain_args, span_help_and_lint, match_type, snippet}; /// vec.push(bench) /// } /// } -///``` +/// ``` /// Could be written: /// /// ```rust @@ -40,13 +40,13 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain! {[ //begin checking variables let ExprMatch(ref op, ref body, ref source) = expr.node, //test if expr is a match let MatchSource::IfLetDesugar { .. } = *source, //test if it is an If Let let ExprMethodCall(_, _, ref result_types) = op.node, //check is expr.ok() has type Result.ok() - let PatKind::TupleStruct(ref x, ref y, _) = body[0].pats[0].node, //get operation + let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node, //get operation method_chain_args(op, &["ok"]).is_some() //test to see if using ok() methoduse std::marker::Sized; ], { diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index ca30c14e191a..4216345e48e7 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -32,8 +32,8 @@ impl LintPass for NonSensical { } } -impl LateLintPass for NonSensical { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSensical { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprMethodCall(ref name, _, ref arguments) = e.node { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.tables().expr_ty(&arguments[0])); if &*name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { @@ -71,36 +71,32 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp let argument_option = match arguments[1].node { ExprLit(ref span) => { if let Spanned { node: LitKind::Bool(lit), .. } = **span { - if lit { - Argument::True - } else { - Argument::False - } + if lit { Argument::True } else { Argument::False } } else { return; // The function is called with a literal // which is not a boolean literal. This is theoretically // possible, but not very likely. } - } + }, _ => Argument::Unknown, }; match &*name.node.as_str() { "create" => { options.push((OpenOption::Create, argument_option)); - } + }, "append" => { options.push((OpenOption::Append, argument_option)); - } + }, "truncate" => { options.push((OpenOption::Truncate, argument_option)); - } + }, "read" => { options.push((OpenOption::Read, argument_option)); - } + }, "write" => { options.push((OpenOption::Write, argument_option)); - } + }, _ => (), } @@ -111,11 +107,8 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); - let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = (false, - false, - false, - false, - false); + let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = + (false, false, false, false, false); // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. for option in options { @@ -130,7 +123,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span create = true } create_arg = create_arg || (arg == Argument::True);; - } + }, (OpenOption::Append, arg) => { if append { span_lint(cx, @@ -141,7 +134,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span append = true } append_arg = append_arg || (arg == Argument::True);; - } + }, (OpenOption::Truncate, arg) => { if truncate { span_lint(cx, @@ -152,7 +145,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span truncate = true } truncate_arg = truncate_arg || (arg == Argument::True); - } + }, (OpenOption::Read, arg) => { if read { span_lint(cx, @@ -163,7 +156,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span read = true } read_arg = read_arg || (arg == Argument::True);; - } + }, (OpenOption::Write, arg) => { if write { span_lint(cx, @@ -174,7 +167,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span write = true } write_arg = write_arg || (arg == Argument::True);; - } + }, } } diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 98c2b986d202..f2e478865497 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -29,27 +29,29 @@ impl LintPass for OverflowCheckConditional { } } -impl LateLintPass for OverflowCheckConditional { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain! {[ let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node, - let Expr_::ExprPath(_,ref path1) = ident1.node, - let Expr_::ExprPath(_, ref path2) = ident2.node, - let Expr_::ExprPath(_, ref path3) = second.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = second.node, &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], cx.tcx.tables().expr_ty(ident1).is_integral(), cx.tcx.tables().expr_ty(ident2).is_integral() ], { if let BinOp_::BiLt = op.node { if let BinOp_::BiAdd = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust."); + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, + "You are trying to use classic C overflow conditions that will fail in Rust."); } } if let BinOp_::BiGt = op.node { if let BinOp_::BiSub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust."); + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, + "You are trying to use classic C underflow conditions that will fail in Rust."); } } }} @@ -57,21 +59,23 @@ impl LateLintPass for OverflowCheckConditional { if_let_chain! {[ let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node, - let Expr_::ExprPath(_,ref path1) = ident1.node, - let Expr_::ExprPath(_, ref path2) = ident2.node, - let Expr_::ExprPath(_, ref path3) = first.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node, + let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = first.node, &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], cx.tcx.tables().expr_ty(ident1).is_integral(), cx.tcx.tables().expr_ty(ident2).is_integral() ], { if let BinOp_::BiGt = op.node { if let BinOp_::BiAdd = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust."); + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, + "You are trying to use classic C overflow conditions that will fail in Rust."); } } if let BinOp_::BiLt = op.node { if let BinOp_::BiSub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust."); + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, + "You are trying to use classic C underflow conditions that will fail in Rust."); } } }} diff --git a/clippy_lints/src/panic.rs b/clippy_lints/src/panic.rs index 97ad9173ef15..3b4fbb3ab1b6 100644 --- a/clippy_lints/src/panic.rs +++ b/clippy_lints/src/panic.rs @@ -32,16 +32,15 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain! {[ let ExprBlock(ref block) = expr.node, let Some(ref ex) = block.expr, let ExprCall(ref fun, ref params) = ex.node, params.len() == 2, - let ExprPath(None, _) = fun.node, - let Some(fun) = resolve_node(cx, fun.id), - match_def_path(cx, fun.def_id(), &paths::BEGIN_PANIC), + let ExprPath(ref qpath) = fun.node, + match_def_path(cx, resolve_node(cx, qpath, fun.id).def_id(), &paths::BEGIN_PANIC), let ExprLit(ref lit) = params[0].node, is_direct_expn_of(cx, params[0].span, "panic").is_some(), let LitKind::Str(ref string, _) = lit.node, diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index fdee5c256e19..2677b40f757a 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -35,12 +35,12 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if_let_chain! {[ let ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) = item.node, !is_automatically_derived(&*item.attrs), - cx.tcx.expect_def(trait_ref.ref_id).def_id() == cx.tcx.lang_items.eq_trait().unwrap(), + trait_ref.path.def.def_id() == cx.tcx.lang_items.eq_trait().unwrap(), ], { for impl_item in impl_items { if &*impl_item.name.as_str() == "ne" { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 1d10fb19c733..146706646ae4 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -49,7 +49,7 @@ impl EarlyLintPass for Precedence { snippet(cx, left.span, ".."), op.to_string(), snippet(cx, right.span, ".."))); - } + }, (true, false) => { span_lint(cx, PRECEDENCE, @@ -59,7 +59,7 @@ impl EarlyLintPass for Precedence { snippet(cx, left.span, ".."), op.to_string(), snippet(cx, right.span, ".."))); - } + }, (false, true) => { span_lint(cx, PRECEDENCE, @@ -69,7 +69,7 @@ impl EarlyLintPass for Precedence { snippet(cx, left.span, ".."), op.to_string(), snippet(cx, right.span, ".."))); - } + }, _ => (), } } @@ -88,7 +88,7 @@ impl EarlyLintPass for Precedence { &format!("unary minus has lower precedence than method call. Consider \ adding parentheses to clarify your intent: -({})", snippet(cx, rhs.span, ".."))); - } + }, _ => (), } } diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index 46d38a67a863..daa55c9675fc 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -2,7 +2,7 @@ use rustc::hir::*; use rustc::hir::map::Node::{NodeItem, NodeImplItem}; use rustc::lint::*; use utils::paths; -use utils::{is_expn_of, match_path, match_def_path, resolve_node, span_lint}; +use utils::{is_expn_of, match_def_path, resolve_node, span_lint, match_path_old}; use format::get_argument_fmtstr_parts; /// **What it does:** This lint warns when you using `print!()` with a format string that @@ -65,13 +65,13 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain! {[ let ExprCall(ref fun, ref args) = expr.node, - let ExprPath(..) = fun.node, - let Some(fun) = resolve_node(cx, fun.id), + let ExprPath(ref qpath) = fun.node, ], { + let fun = resolve_node(cx, qpath, fun.id); let fun_id = fun.def_id(); // Search for `std::io::_print(..)` which is unique in a @@ -93,9 +93,8 @@ impl LateLintPass for Pass { // ensure we're calling Arguments::new_v1 args.len() == 1, let ExprCall(ref args_fun, ref args_args) = args[0].node, - let ExprPath(..) = args_fun.node, - let Some(def) = resolve_node(cx, args_fun.id), - match_def_path(cx, def.def_id(), &paths::FMT_ARGUMENTS_NEWV1), + let ExprPath(ref qpath) = args_fun.node, + match_def_path(cx, resolve_node(cx, qpath, args_fun.id).def_id(), &paths::FMT_ARGUMENTS_NEWV1), args_args.len() == 2, let ExprAddrOf(_, ref match_expr) = args_args[1].node, let ExprMatch(ref args, _, _) = match_expr.node, @@ -121,8 +120,8 @@ impl LateLintPass for Pass { // Search for something like // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` else if args.len() == 2 && match_def_path(cx, fun_id, &paths::FMT_ARGUMENTV1_NEW) { - if let ExprPath(None, _) = args[1].node { - let def_id = resolve_node(cx, args[1].id).unwrap().def_id(); + if let ExprPath(ref qpath) = args[1].node { + let def_id = cx.tcx.tables().qpath_def(qpath, args[1].id).def_id(); if match_def_path(cx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) && is_expn_of(cx, expr.span, "panic").is_none() { span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting"); @@ -141,7 +140,7 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { // `Debug` impl if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) { if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node { - return match_path(&tr.path, &["Debug"]); + return match_path_old(&tr.path, &["Debug"]); } } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2863b14b1121..2f74390cc73e 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -54,14 +54,14 @@ impl LintPass for PointerPass { } } -impl LateLintPass for PointerPass { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemFn(ref decl, _, _, _, _, _) = item.node { check_fn(cx, decl, item.id); } } - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) { if let ImplItemKind::Method(ref sig, _) = item.node { if let Some(NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { if let ItemImpl(_, _, _, Some(_), _, _) = it.node { @@ -72,13 +72,13 @@ impl LateLintPass for PointerPass { } } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { check_fn(cx, &sig.decl, item.id); } } - - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprBinary(ref op, ref l, ref r) = expr.node { if (op.node == BiEq || op.node == BiNe) && (is_null_path(l) || is_null_path(r)) { span_lint(cx, @@ -94,7 +94,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { let fn_def_id = cx.tcx.map.local_def_id(fn_id); let fn_ty = cx.tcx.item_type(fn_def_id).fn_sig().skip_binder(); - for (arg, ty) in decl.inputs.iter().zip(&fn_ty.inputs) { + for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { if match_type(cx, ty, &paths::VEC) { span_lint(cx, @@ -116,8 +116,8 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { fn is_null_path(expr: &Expr) -> bool { if let ExprCall(ref pathexp, ref args) = expr.node { if args.is_empty() { - if let ExprPath(_, ref path) = pathexp.node { - return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT) + if let ExprPath(ref path) = pathexp.node { + return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT); } } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index ab02a62ad292..01829ffea45b 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -46,14 +46,13 @@ impl LintPass for StepByZero { } } -impl LateLintPass for StepByZero { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { let name = &*name.as_str(); // Range with step_by(0). - if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && - is_integer_literal(&args[1], 0) { + if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && is_integer_literal(&args[1], 0) { span_lint(cx, RANGE_STEP_BY_ZERO, expr.span, @@ -73,15 +72,15 @@ impl LateLintPass for StepByZero { let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = end.node, &*len_name.as_str() == "len" && len_args.len() == 1, // .iter() and .len() called on same Path - let ExprPath(_, Path { segments: ref iter_path, .. }) = iter_args[0].node, - let ExprPath(_, Path { segments: ref len_path, .. }) = len_args[0].node, - iter_path == len_path + let ExprPath(QPath::Resolved(_, ref iter_path)) = iter_args[0].node, + let ExprPath(QPath::Resolved(_, ref len_path)) = len_args[0].node, + iter_path.segments == len_path.segments ], { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - expr.span, - &format!("It is more idiomatic to use {}.iter().enumerate()", - snippet(cx, iter_args[0].span, "_"))); + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("It is more idiomatic to use {}.iter().enumerate()", + snippet(cx, iter_args[0].span, "_"))); }} } } @@ -94,7 +93,6 @@ fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { let ty = cx.tcx.tables().expr_ty(expr); // Note: `RangeTo`, `RangeToInclusive` and `RangeFull` don't have step_by - match_type(cx, ty, &paths::RANGE) - || match_type(cx, ty, &paths::RANGE_FROM) - || match_type(cx, ty, &paths::RANGE_INCLUSIVE) + match_type(cx, ty, &paths::RANGE) || match_type(cx, ty, &paths::RANGE_FROM) || + match_type(cx, ty, &paths::RANGE_INCLUSIVE) } diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs new file mode 100644 index 000000000000..7c5c5713550a --- /dev/null +++ b/clippy_lints/src/reference.rs @@ -0,0 +1,49 @@ +use syntax::ast::{Expr, ExprKind, UnOp}; +use rustc::lint::*; +use utils::{span_lint_and_then, snippet}; + +/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. +/// +/// **Why is this bad?** Immediately dereferencing a reference is no-op and +/// makes the code less clear. +/// +/// **Known problems:** Multiple dereference/addrof pairs are not handled so +/// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect. +/// +/// **Example:** +/// ```rust +/// let a = f(*&mut b); +/// let c = *&d; +/// ``` +declare_lint! { + pub DEREF_ADDROF, + Warn, + "use of `*&` or `*&mut` in an expression" +} + +pub struct Pass; + +impl LintPass for Pass { + fn get_lints(&self) -> LintArray { + lint_array!(DEREF_ADDROF) + } +} + +fn without_parens(mut e: &Expr) -> &Expr { + while let ExprKind::Paren(ref child_e) = e.node { + e = child_e; + } + e +} + +impl EarlyLintPass for Pass { + fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { + if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node { + if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node { + span_lint_and_then(cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", |db| { + db.span_suggestion(e.span, "try this", format!("{}", snippet(cx, addrof_target.span, "_"))); + }); + } + } + } +} diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index ec3013d36a1b..31ac194ca7bf 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -82,12 +82,12 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_crate(&mut self, _: &LateContext, _: &Crate) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx Crate) { self.spans.clear(); } - fn check_block(&mut self, cx: &LateContext, block: &Block) { + fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) { if_let_chain!{[ self.last.is_none(), let Some(ref expr) = block.expr, @@ -106,19 +106,19 @@ impl LateLintPass for Pass { }} } - fn check_block_post(&mut self, _: &LateContext, block: &Block) { + fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, block: &'tcx Block) { if self.last.map_or(false, |id| block.id == id) { self.last = None; } } - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain!{[ let ExprCall(ref fun, ref args) = expr.node, + let ExprPath(ref qpath) = fun.node, args.len() == 1, - let Some(def) = cx.tcx.def_map.borrow().get(&fun.id), ], { - let def_id = def.full_def().def_id(); + let def_id = cx.tcx.tables().qpath_def(qpath, fun.id).def_id(); if match_def_path(cx, def_id, &paths::REGEX_NEW) || match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { check_regex(cx, &args[0], true); @@ -145,7 +145,7 @@ fn str_span(base: Span, s: &str, c: usize) -> Span { hi: base.lo + BytePos(h as u32), ..base } - } + }, _ => base, } } @@ -172,17 +172,18 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { (&Expr::Literal { .. }, &Expr::EndText) => Some("consider using `str::ends_with`"), _ => None, } - } + }, 3 => { - if let (&Expr::StartText, &Expr::Literal {..}, &Expr::EndText) = (&exprs[0], &exprs[1], &exprs[2]) { + if let (&Expr::StartText, &Expr::Literal { .. }, &Expr::EndText) = + (&exprs[0], &exprs[1], &exprs[2]) { Some("consider using `==` on `str`s") } else { None } - } + }, _ => None, } - } + }, _ => None, } } @@ -213,14 +214,13 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { "trivial regex", &format!("consider using {}", repl)); } - } + }, Err(e) => { span_lint(cx, INVALID_REGEX, str_span(expr.span, r, e.position()), - &format!("regex syntax error: {}", - e.description())); - } + &format!("regex syntax error: {}", e.description())); + }, } } } else if let Some(r) = const_str(cx, expr) { @@ -233,15 +233,13 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { "trivial regex", &format!("consider using {}", repl)); } - } + }, Err(e) => { span_lint(cx, INVALID_REGEX, expr.span, - &format!("regex syntax error on position {}: {}", - e.position(), - e.description())); - } + &format!("regex syntax error on position {}: {}", e.position(), e.description())); + }, } } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d79913b2c15b..b9054f72164b 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -48,9 +48,10 @@ impl ReturnPass { fn check_block_return(&mut self, cx: &EarlyContext, block: &ast::Block) { if let Some(stmt) = block.stmts.last() { match stmt.node { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => { + ast::StmtKind::Expr(ref expr) | + ast::StmtKind::Semi(ref expr) => { self.check_final_expr(cx, expr, Some(stmt.span)); - } + }, _ => (), } } @@ -65,24 +66,24 @@ impl ReturnPass { if !expr.attrs.iter().any(attr_is_cfg) { self.emit_return_lint(cx, span.expect("`else return` is not possible"), inner.span); } - } + }, // a whole block? check it! ast::ExprKind::Block(ref block) => { self.check_block_return(cx, block); - } + }, // an if/if let expr, check both exprs // note, if without else is going to be a type checking error anyways // (except for unit type functions) so we don't match it ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { self.check_block_return(cx, ifblock); self.check_final_expr(cx, elsexpr, None); - } + }, // a match expr, check all arms ast::ExprKind::Match(_, ref arms) => { for arm in arms { self.check_final_expr(cx, &arm.body, Some(arm.body.span)); } - } + }, _ => (), } } @@ -135,7 +136,8 @@ impl LintPass for ReturnPass { impl EarlyLintPass for ReturnPass { fn check_fn(&mut self, cx: &EarlyContext, kind: FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { match kind { - FnKind::ItemFn(.., block) | FnKind::Method(.., block) => self.check_block_return(cx, block), + FnKind::ItemFn(.., block) | + FnKind::Method(.., block) => self.check_block_return(cx, block), FnKind::Closure(body) => self.check_final_expr(cx, body, None), } } @@ -152,4 +154,3 @@ fn attr_is_cfg(attr: &ast::Attribute) -> bool { false } } - diff --git a/clippy_lints/src/serde.rs b/clippy_lints/src/serde.rs index 6cf10d883d31..02faf7a204fb 100644 --- a/clippy_lints/src/serde.rs +++ b/clippy_lints/src/serde.rs @@ -26,10 +26,10 @@ impl LintPass for Serde { } } -impl LateLintPass for Serde { - fn check_item(&mut self, cx: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemImpl(_, _, _, Some(ref trait_ref), _, ref items) = item.node { - let did = cx.tcx.expect_def(trait_ref.ref_id).def_id(); + let did = trait_ref.path.def.def_id(); if let Some(visit_did) = get_trait_def_id(cx, &paths::SERDE_DE_VISITOR) { if did == visit_did { let mut seen_str = None; @@ -46,8 +46,7 @@ impl LateLintPass for Serde { span_lint(cx, SERDE_API_MISUSE, span, - "you should not implement `visit_string` without also implementing `visit_str`", - ); + "you should not implement `visit_string` without also implementing `visit_str`"); } } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index d23b1c9993fe..9c5b032f6251 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,9 +1,8 @@ use reexport::*; use rustc::lint::*; -use rustc::hir::def::Def; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, FnKind}; -use std::ops::Deref; +use rustc::hir::intravisit::{Visitor, FnKind, NestedVisitorMap}; +use rustc::ty; use syntax::codemap::Span; use utils::{higher, in_external_macro, snippet, span_lint_and_then}; @@ -80,8 +79,16 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, expr: &Expr, _: Span, _: NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + decl: &'tcx FnDecl, + expr: &'tcx Expr, + _: Span, + _: NodeId + ) { if in_external_macro(cx, expr.span) { return; } @@ -89,17 +96,17 @@ impl LateLintPass for Pass { } } -fn check_fn(cx: &LateContext, decl: &FnDecl, expr: &Expr) { +fn check_fn<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, expr: &'tcx Expr) { let mut bindings = Vec::new(); for arg in &decl.inputs { - if let PatKind::Binding(_, ident, _) = arg.pat.node { + if let PatKind::Binding(_, _, ident, _) = arg.pat.node { bindings.push((ident.node, ident.span)) } } check_expr(cx, expr, &mut bindings); } -fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>) { +fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, bindings: &mut Vec<(Name, Span)>) { let len = bindings.len(); for stmt in &block.stmts { match stmt.node { @@ -114,7 +121,7 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)> bindings.truncate(len); } -fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { +fn check_decl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } @@ -128,27 +135,33 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { } if let Some(ref o) = *init { check_expr(cx, o, bindings); - check_pat(cx, pat, &Some(o), span, bindings); + check_pat(cx, pat, Some(o), span, bindings); } else { - check_pat(cx, pat, &None, span, bindings); + check_pat(cx, pat, None, span, bindings); } } } -fn is_binding(cx: &LateContext, pat: &Pat) -> bool { - match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { - Some(Def::Variant(..)) | - Some(Def::Struct(..)) => false, +fn is_binding(cx: &LateContext, pat_id: NodeId) -> bool { + let var_ty = cx.tcx.tables().node_id_to_type(pat_id); + match var_ty.sty { + ty::TyAdt(..) => false, _ => true, } } -fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { +fn check_pat<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + pat: &'tcx Pat, + init: Option<&'tcx Expr>, + span: Span, + bindings: &mut Vec<(Name, Span)> +) { // TODO: match more stuff / destructuring match pat.node { - PatKind::Binding(_, ref ident, ref inner) => { + PatKind::Binding(_, _, ref ident, ref inner) => { let name = ident.node; - if is_binding(cx, pat) { + if is_binding(cx, pat.id) { let mut new_binding = true; for tup in bindings.iter_mut() { if tup.0 == name { @@ -165,16 +178,16 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } - } + }, PatKind::Struct(_, ref pfields, _) => { - if let Some(init_struct) = *init { + if let Some(init_struct) = init { if let ExprStruct(_, ref efields, _) = init_struct.node { for field in pfields { let name = field.node.name; let efield = efields.iter() - .find(|f| f.name.node == name) - .map(|f| &*f.expr); - check_pat(cx, &field.node.pat, &efield, span, bindings); + .find(|f| f.name.node == name) + .map(|f| &*f.expr); + check_pat(cx, &field.node.pat, efield, span, bindings); } } else { for field in pfields { @@ -183,15 +196,15 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } else { for field in pfields { - check_pat(cx, &field.node.pat, &None, span, bindings); + check_pat(cx, &field.node.pat, None, span, bindings); } } - } + }, PatKind::Tuple(ref inner, _) => { - if let Some(init_tup) = *init { + if let Some(init_tup) = init { if let ExprTup(ref tup) = init_tup.node { for (i, p) in inner.iter().enumerate() { - check_pat(cx, p, &Some(&tup[i]), p.span, bindings); + check_pat(cx, p, Some(&tup[i]), p.span, bindings); } } else { for p in inner { @@ -200,31 +213,36 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } else { for p in inner { - check_pat(cx, p, &None, span, bindings); + check_pat(cx, p, None, span, bindings); } } - } + }, PatKind::Box(ref inner) => { - if let Some(initp) = *init { + if let Some(initp) = init { if let ExprBox(ref inner_init) = initp.node { - check_pat(cx, inner, &Some(&**inner_init), span, bindings); + check_pat(cx, inner, Some(&**inner_init), span, bindings); } else { check_pat(cx, inner, init, span, bindings); } } else { check_pat(cx, inner, init, span, bindings); } - } + }, PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings), // PatVec(Vec>, Option>, Vec>), _ => (), } } -fn lint_shadow(cx: &LateContext, name: Name, span: Span, pattern_span: Span, init: &Option, prev_span: Span) - where T: Deref -{ - if let Some(ref expr) = *init { +fn lint_shadow<'a, 'tcx: 'a>( + cx: &LateContext<'a, 'tcx>, + name: Name, + span: Span, + pattern_span: Span, + init: Option<&'tcx Expr>, + prev_span: Span +) { + if let Some(expr) = init { if is_self_shadow(name, expr) { span_lint_and_then(cx, SHADOW_SAME, @@ -232,9 +250,10 @@ fn lint_shadow(cx: &LateContext, name: Name, span: Span, pattern_span: Span, &format!("`{}` is shadowed by itself in `{}`", snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), - |db| { db.span_note(prev_span, "previous binding is here"); }, - ); - } else if contains_self(name, expr) { + |db| { + db.span_note(prev_span, "previous binding is here"); + }); + } else if contains_self(cx, name, expr) { span_lint_and_then(cx, SHADOW_REUSE, pattern_span, @@ -242,9 +261,9 @@ fn lint_shadow(cx: &LateContext, name: Name, span: Span, pattern_span: Span, snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), |db| { - db.span_note(expr.span, "initialization happens here"); - db.span_note(prev_span, "previous binding is here"); - }); + db.span_note(expr.span, "initialization happens here"); + db.span_note(prev_span, "previous binding is here"); + }); } else { span_lint_and_then(cx, SHADOW_UNRELATED, @@ -253,9 +272,9 @@ fn lint_shadow(cx: &LateContext, name: Name, span: Span, pattern_span: Span, snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), |db| { - db.span_note(expr.span, "initialization happens here"); - db.span_note(prev_span, "previous binding is here"); - }); + db.span_note(expr.span, "initialization happens here"); + db.span_note(prev_span, "previous binding is here"); + }); } } else { @@ -263,11 +282,13 @@ fn lint_shadow(cx: &LateContext, name: Name, span: Span, pattern_span: Span, SHADOW_UNRELATED, span, &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), - |db| { db.span_note(prev_span, "previous binding is here"); }); + |db| { + db.span_note(prev_span, "previous binding is here"); + }); } } -fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { +fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, expr.span) { return; } @@ -285,24 +306,24 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { for e in v { check_expr(cx, e, bindings) } - } + }, ExprIf(ref cond, ref then, ref otherwise) => { check_expr(cx, cond, bindings); check_block(cx, then, bindings); if let Some(ref o) = *otherwise { check_expr(cx, o, bindings); } - } + }, ExprWhile(ref cond, ref block, _) => { check_expr(cx, cond, bindings); check_block(cx, block, bindings); - } + }, ExprMatch(ref init, ref arms, _) => { check_expr(cx, init, bindings); let len = bindings.len(); for arm in arms { for pat in &arm.pats { - check_pat(cx, pat, &Some(&**init), pat.span, bindings); + check_pat(cx, pat, Some(&**init), pat.span, bindings); // This is ugly, but needed to get the right type if let Some(ref guard) = arm.guard { check_expr(cx, guard, bindings); @@ -311,26 +332,26 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { bindings.truncate(len); } } - } + }, _ => (), } } -fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { +fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut Vec<(Name, Span)>) { match ty.node { TyObjectSum(ref sty, _) | TySlice(ref sty) => check_ty(cx, sty, bindings), TyArray(ref fty, ref expr) => { check_ty(cx, fty, bindings); check_expr(cx, expr, bindings); - } + }, TyPtr(MutTy { ty: ref mty, .. }) | TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings), TyTup(ref tup) => { for t in tup { check_ty(cx, t, bindings) } - } + }, TyTypeof(ref expr) => check_expr(cx, expr, bindings), _ => (), } @@ -342,9 +363,9 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprBlock(ref block) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) - } + }, ExprUnary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner), - ExprPath(_, ref path) => path_eq_name(name, path), + ExprPath(QPath::Resolved(_, ref path)) => path_eq_name(name, path), _ => false, } } @@ -353,23 +374,28 @@ fn path_eq_name(name: Name, path: &Path) -> bool { !path.global && path.segments.len() == 1 && path.segments[0].name.as_str() == name.as_str() } -struct ContainsSelf { +struct ContainsSelf<'a, 'tcx: 'a> { name: Name, result: bool, + cx: &'a LateContext<'a, 'tcx>, } -impl<'v> Visitor<'v> for ContainsSelf { +impl<'a, 'tcx: 'a> Visitor<'tcx> for ContainsSelf<'a, 'tcx> { fn visit_name(&mut self, _: Span, name: Name) { if self.name == name { self.result = true; } } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } -fn contains_self(name: Name, expr: &Expr) -> bool { +fn contains_self<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, expr: &'tcx Expr) -> bool { let mut cs = ContainsSelf { name: name, result: false, + cx: cx, }; cs.visit_expr(expr); cs.result diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index e971d6ee13fc..195b49c72f68 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -79,8 +79,8 @@ impl LintPass for StringAdd { } } -impl LateLintPass for StringAdd { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) = e.node { if is_string(cx, left) { if let Allow = cx.current_level(STRING_ADD_ASSIGN) { @@ -122,7 +122,7 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), ExprBlock(ref block) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) - } + }, _ => false, } } @@ -136,8 +136,8 @@ impl LintPass for StringLitAsBytes { } } -impl LateLintPass for StringLitAsBytes { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { use std::ascii::AsciiExt; use syntax::ast::LitKind; use utils::{snippet, in_macro}; @@ -152,11 +152,9 @@ impl LateLintPass for StringLitAsBytes { e.span, "calling `as_bytes()` on a string literal", |db| { - let sugg = format!("b{}", snippet(cx, args[0].span, r#""foo""#)); - db.span_suggestion(e.span, - "consider using a byte string literal instead", - sugg); - }); + let sugg = format!("b{}", snippet(cx, args[0].span, r#""foo""#)); + db.span_suggestion(e.span, "consider using a byte string literal instead", sugg); + }); } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 278df3bad352..8ed7e3558797 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -50,8 +50,8 @@ impl LintPass for Swap { } } -impl LateLintPass for Swap { - fn check_block(&mut self, cx: &LateContext, block: &Block) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap { + fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) { check_manual_swap(cx, block); check_suspicious_swap(cx, block); } @@ -65,7 +65,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { let StmtDecl(ref tmp, _) = w[0].node, let DeclLocal(ref tmp) = tmp.node, let Some(ref tmp_init) = tmp.init, - let PatKind::Binding(_, ref tmp_name, None) = tmp.pat.node, + let PatKind::Binding(_, _, ref tmp_name, None) = tmp.pat.node, // foo() = bar(); let StmtSemi(ref first, _) = w[1].node, @@ -74,14 +74,18 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { // bar() = t; let StmtSemi(ref second, _) = w[2].node, let ExprAssign(ref lhs2, ref rhs2) = second.node, - let ExprPath(None, ref rhs2) = rhs2.node, + let ExprPath(QPath::Resolved(None, ref rhs2)) = rhs2.node, rhs2.segments.len() == 1, tmp_name.node.as_str() == rhs2.segments[0].name.as_str(), SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1), SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2) ], { - fn check_for_slice<'a>(cx: &LateContext, lhs1: &'a Expr, lhs2: &'a Expr) -> Option<(&'a Expr, &'a Expr, &'a Expr)> { + fn check_for_slice<'a>( + cx: &LateContext, + lhs1: &'a Expr, + lhs2: &'a Expr, + ) -> Option<(&'a Expr, &'a Expr, &'a Expr)> { if let ExprIndex(ref lhs1, ref idx1) = lhs1.node { if let ExprIndex(ref lhs2, ref idx2) = lhs2.node { if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) { @@ -104,7 +108,10 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { if let Some(slice) = Sugg::hir_opt(cx, slice) { (false, format!(" elements of `{}`", slice), - format!("{}.swap({}, {})", slice.maybe_par(), snippet(cx, idx1.span, ".."), snippet(cx, idx2.span, ".."))) + format!("{}.swap({}, {})", + slice.maybe_par(), + snippet(cx, idx1.span, ".."), + snippet(cx, idx2.span, ".."))) } else { (false, "".to_owned(), "".to_owned()) } @@ -148,7 +155,9 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1), SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0) ], { - let (what, lhs, rhs) = if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs0), Sugg::hir_opt(cx, rhs0)) { + let lhs0 = Sugg::hir_opt(cx, lhs0); + let rhs0 = Sugg::hir_opt(cx, rhs0); + let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) { (format!(" `{}` and `{}`", first, second), first.mut_addr().to_string(), second.mut_addr().to_string()) } else { ("".to_owned(), "".to_owned(), "".to_owned()) diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 5b5802695bb8..1669b2d65572 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -37,8 +37,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprAssign(ref target, _) = expr.node { match target.node { ExprField(ref base, _) | @@ -46,7 +46,7 @@ impl LateLintPass for Pass { if is_temporary(base) && !is_adjusted(cx, base) { span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } - } + }, _ => (), } } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index a7e16a56f386..5e01f891eb17 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; use rustc::ty; use rustc::hir::*; -use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet}; +use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet, last_path_segment}; use utils::sugg; /// **What it does:** Checks for transmutes that can't ever be correct on any @@ -84,29 +84,29 @@ impl LintPass for Transmute { } } -impl LateLintPass for Transmute { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprCall(ref path_expr, ref args) = e.node { - if let ExprPath(None, ref path) = path_expr.node { - let def_id = cx.tcx.expect_def(path_expr.id).def_id(); + if let ExprPath(ref qpath) = path_expr.node { + let def_id = cx.tcx.tables().qpath_def(qpath, path_expr.id).def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE) { let from_ty = cx.tcx.tables().expr_ty(&args[0]); let to_ty = cx.tcx.tables().expr_ty(e); match (&from_ty.sty, &to_ty.sty) { - _ if from_ty == to_ty => span_lint( - cx, - USELESS_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to itself", from_ty), - ), - (&TyRef(_, rty), &TyRawPtr(ptr_ty)) => span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from a reference to a pointer", - |db| { + _ if from_ty == to_ty => { + span_lint(cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty)) + }, + (&TyRef(_, rty), &TyRawPtr(ptr_ty)) => { + span_lint_and_then(cx, + USELESS_TRANSMUTE, + e.span, + "transmute from a reference to a pointer", + |db| { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { let sugg = if ptr_ty == rty { arg.as_ty(to_ty) @@ -116,53 +116,54 @@ impl LateLintPass for Transmute { db.span_suggestion(e.span, "try", sugg.to_string()); } - }, - ), + }) + }, (&ty::TyInt(_), &TyRawPtr(_)) | - (&ty::TyUint(_), &TyRawPtr(_)) => span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |db| { + (&ty::TyUint(_), &TyRawPtr(_)) => { + span_lint_and_then(cx, + USELESS_TRANSMUTE, + e.span, + "transmute from an integer to a pointer", + |db| { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string()); } - }, - ), + }) + }, (&ty::TyFloat(_), &TyRef(..)) | (&ty::TyFloat(_), &TyRawPtr(_)) | (&ty::TyChar, &TyRef(..)) | - (&ty::TyChar, &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 => span_lint( - cx, - CROSSPOINTER_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", - from_ty, - to_ty), - ), - (_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( - cx, - CROSSPOINTER_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", - from_ty, - to_ty), - ), - (&TyRawPtr(from_pty), &TyRef(_, to_rty)) => span_lint_and_then( - cx, - TRANSMUTE_PTR_TO_REF, - e.span, - &format!("transmute from a pointer type (`{}`) to a reference type (`{}`)", - from_ty, - to_ty), - |db| { + (&ty::TyChar, &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 => { + span_lint(cx, + CROSSPOINTER_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", + from_ty, + to_ty)) + }, + (_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => { + span_lint(cx, + CROSSPOINTER_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", + from_ty, + to_ty)) + }, + (&TyRawPtr(from_pty), &TyRef(_, to_rty)) => { + span_lint_and_then(cx, + TRANSMUTE_PTR_TO_REF, + e.span, + &format!("transmute from a pointer type (`{}`) to a reference type \ + (`{}`)", + from_ty, + to_ty), + |db| { let arg = sugg::Sugg::hir(cx, &args[0], ".."); let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable { ("&mut *", "*mut") @@ -173,12 +174,12 @@ impl LateLintPass for Transmute { let arg = if from_pty.ty == to_rty.ty { arg } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, path, to_rty.ty))) + arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_rty.ty))) }; db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string()); - }, - ), + }) + }, _ => return, }; } @@ -190,9 +191,9 @@ impl LateLintPass for Transmute { /// Get the snippet of `Bar` in `…::transmute`. If that snippet is not available , use /// the type's `ToString` implementation. In weird cases it could lead to types with invalid `'_` /// lifetime, but it should be rare. -fn get_type_snippet(cx: &LateContext, path: &Path, to_rty: ty::Ty) -> String { +fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: ty::Ty) -> String { + let seg = last_path_segment(path); if_let_chain!{[ - let Some(seg) = path.segments.last(), let PathParameters::AngleBracketedParameters(ref ang) = seg.parameters, let Some(to_ty) = ang.types.get(1), let TyRptr(_, ref to_ty) = to_ty.node, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index de8fbdcc5d7a..5885d7863b71 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,13 +1,13 @@ use reexport::*; use rustc::hir::*; -use rustc::hir::intravisit::{FnKind, Visitor, walk_ty}; +use rustc::hir::intravisit::{FnKind, Visitor, walk_ty, NestedVisitorMap}; use rustc::lint::*; use rustc::ty; use std::cmp::Ordering; use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; -use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, - span_help_and_lint, span_lint}; +use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, + opt_def_id, last_path_segment}; use utils::paths; /// Handles all the linting of funky types @@ -69,38 +69,107 @@ impl LintPass for TypePass { } } -impl LateLintPass for TypePass { - fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) { - if in_macro(cx, ast_ty.span) { - return; +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Expr, _: 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 ItemImpl(_, _, _, Some(..), _, _) = item.node { + return; + } } - if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) { - if let def::Def::Struct(..) = did.full_def() { - if Some(did.full_def().def_id()) == cx.tcx.lang_items.owned_box() { + + check_fn_decl(cx, decl); + } + + fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { + check_ty(cx, &field.ty); + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + match item.node { + ConstTraitItem(ref ty, _) | + TypeTraitItem(_, Some(ref ty)) => check_ty(cx, ty), + MethodTraitItem(ref sig, _) => check_fn_decl(cx, &sig.decl), + _ => (), + } + } +} + +fn check_fn_decl(cx: &LateContext, decl: &FnDecl) { + for input in &decl.inputs { + check_ty(cx, &input.ty); + } + + if let FunctionRetTy::Return(ref ty) = decl.output { + check_ty(cx, ty); + } +} + +fn check_ty(cx: &LateContext, ast_ty: &Ty) { + if in_macro(cx, ast_ty.span) { + return; + } + match ast_ty.node { + TyPath(ref qpath) => { + let def = cx.tcx.tables().qpath_def(qpath, ast_ty.id); + if let Some(def_id) = opt_def_id(def) { + if Some(def_id) == cx.tcx.lang_items.owned_box() { + let last = last_path_segment(qpath); if_let_chain! {[ - let TyPath(_, ref path) = ast_ty.node, - let Some(ref last) = path.segments.last(), let PathParameters::AngleBracketedParameters(ref ag) = last.parameters, let Some(ref vec) = ag.types.get(0), - let Some(did) = cx.tcx.def_map.borrow().get(&vec.id), - let def::Def::Struct(..) = did.full_def(), - match_def_path(cx, did.full_def().def_id(), &paths::VEC), + let TyPath(ref qpath) = vec.node, + let def::Def::Struct(..) = cx.tcx.tables().qpath_def(qpath, vec.id), + let Some(did) = opt_def_id(cx.tcx.tables().qpath_def(qpath, vec.id)), + match_def_path(cx, did, &paths::VEC), ], { span_help_and_lint(cx, BOX_VEC, ast_ty.span, "you seem to be trying to use `Box>`. Consider using just `Vec`", "`Vec` is already on the heap, `Box>` makes an extra allocation."); + return; // don't recurse into the type }} - } else if match_def_path(cx, did.full_def().def_id(), &paths::LINKED_LIST) { + } else if match_def_path(cx, def_id, &paths::LINKED_LIST) { span_help_and_lint(cx, LINKEDLIST, ast_ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", "a VecDeque might work"); + return; // don't recurse into the type } } - } + match *qpath { + QPath::Resolved(Some(ref ty), ref p) => { + check_ty(cx, ty); + for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) { + check_ty(cx, ty); + } + }, + QPath::Resolved(None, ref p) => { + for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) { + check_ty(cx, ty); + } + }, + QPath::TypeRelative(ref ty, ref seg) => { + check_ty(cx, ty); + for ty in seg.parameters.types() { + check_ty(cx, ty); + } + }, + } + }, + // recurse + TySlice(ref ty) | + TyArray(ref ty, _) | + TyPtr(MutTy { ref ty, .. }) | + TyRptr(_, MutTy { ref ty, .. }) => check_ty(cx, ty), + TyTup(ref tys) => { + for ty in tys { + check_ty(cx, ty); + } + }, + _ => {}, } } @@ -140,7 +209,7 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) { decl.span, &format!("this let-binding has unit value. Consider omitting `let {} =`", snippet(cx, local.pat.span, ".."))); - } + }, _ => (), } } @@ -152,8 +221,8 @@ impl LintPass for LetPass { } } -impl LateLintPass for LetPass { - fn check_decl(&mut self, cx: &LateContext, decl: &Decl) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetPass { + fn check_decl(&mut self, cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl) { check_let_unit(cx, decl) } } @@ -189,8 +258,8 @@ impl LintPass for UnitCmp { } } -impl LateLintPass for UnitCmp { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if in_macro(cx, expr.span) { return; } @@ -210,8 +279,8 @@ impl LateLintPass for UnitCmp { &format!("{}-comparison of unit values detected. This will always be {}", op.as_str(), result)); - } - _ => () + }, + _ => (), } } } @@ -335,11 +404,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) { - let mantissa_nbits = if cast_to_f64 { - 52 - } else { - 23 - }; + 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 "; let from_nbits_str = if arch_dependent { @@ -355,11 +420,7 @@ fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, &format!("casting {0} to {1} causes a loss of precision {2}({0} is {3} bits wide, but {1}'s mantissa \ is only {4} bits wide)", cast_from, - if cast_to_f64 { - "f64" - } else { - "f32" - }, + if cast_to_f64 { "f64" } else { "f32" }, if arch_dependent { arch_dependent_str } else { @@ -387,27 +448,27 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty:: ArchSuffix::None, to_nbits == from_nbits && cast_unsigned_to_signed, ArchSuffix::None) - } + }, (true, false) => { (to_nbits <= 32, if to_nbits == 32 { - ArchSuffix::_64 - } else { - ArchSuffix::None - }, + ArchSuffix::_64 + } else { + ArchSuffix::None + }, to_nbits <= 32 && cast_unsigned_to_signed, ArchSuffix::_32) - } + }, (false, true) => { (from_nbits == 64, ArchSuffix::_32, cast_unsigned_to_signed, if from_nbits == 64 { - ArchSuffix::_64 - } else { - ArchSuffix::_32 - }) - } + ArchSuffix::_64 + } else { + ArchSuffix::_32 + }) + }, }; if span_truncation { span_lint(cx, @@ -446,8 +507,8 @@ impl LintPass for CastPass { } } -impl LateLintPass for CastPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprCast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tcx.tables().expr_ty(ex), cx.tcx.tables().expr_ty(expr)); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { @@ -462,7 +523,7 @@ impl LateLintPass for CastPass { if is_isize_or_usize(cast_from) || from_nbits >= to_nbits { span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64); } - } + }, (false, true) => { span_lint(cx, CAST_POSSIBLE_TRUNCATION, @@ -474,7 +535,7 @@ impl LateLintPass for CastPass { expr.span, &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); } - } + }, (true, true) => { if cast_from.is_signed() && !cast_to.is_signed() { span_lint(cx, @@ -483,16 +544,16 @@ impl LateLintPass for CastPass { &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); } check_truncation_and_wrapping(cx, expr, cast_from, cast_to); - } + }, (false, false) => { - if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = (&cast_from.sty, - &cast_to.sty) { + if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = + (&cast_from.sty, &cast_to.sty) { span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may truncate the value"); } - } + }, } } } @@ -534,17 +595,25 @@ impl LintPass for TypeComplexityPass { } } -impl LateLintPass for TypeComplexityPass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Expr, _: Span, _: NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + decl: &'tcx FnDecl, + _: &'tcx Expr, + _: Span, + _: NodeId + ) { self.check_fndecl(cx, decl); } - fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { + fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx StructField) { // enum variants are also struct fields now self.check_type(cx, &field.ty); } - fn check_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { match item.node { ItemStatic(ref ty, _, _) | ItemConst(ref ty, _) => self.check_type(cx, ty), @@ -553,7 +622,7 @@ impl LateLintPass for TypeComplexityPass { } } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { match item.node { ConstTraitItem(ref ty, _) | TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty), @@ -563,7 +632,7 @@ impl LateLintPass for TypeComplexityPass { } } - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) { match item.node { ImplItemKind::Const(ref ty, _) | ImplItemKind::Type(ref ty) => self.check_type(cx, ty), @@ -572,15 +641,15 @@ impl LateLintPass for TypeComplexityPass { } } - fn check_local(&mut self, cx: &LateContext, local: &Local) { + fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) { if let Some(ref ty) = local.ty { self.check_type(cx, ty); } } } -impl TypeComplexityPass { - fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) { +impl<'a, 'tcx> TypeComplexityPass { + fn check_fndecl(&self, cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl) { for arg in &decl.inputs { self.check_type(cx, &arg.ty); } @@ -589,7 +658,7 @@ impl TypeComplexityPass { } } - fn check_type(&self, cx: &LateContext, ty: &Ty) { + fn check_type(&self, cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty) { if in_macro(cx, ty.span) { return; } @@ -597,6 +666,7 @@ impl TypeComplexityPass { let mut visitor = TypeComplexityVisitor { score: 0, nest: 1, + cx: cx, }; visitor.visit_ty(ty); visitor.score @@ -612,24 +682,22 @@ impl TypeComplexityPass { } /// Walks a type and assigns a complexity score to it. -struct TypeComplexityVisitor { +struct TypeComplexityVisitor<'a, 'tcx: 'a> { /// total complexity score of the type score: u64, /// current nesting level nest: u64, + cx: &'a LateContext<'a, 'tcx>, } -impl<'v> Visitor<'v> for TypeComplexityVisitor { - fn visit_ty(&mut self, ty: &'v Ty) { +impl<'a, 'tcx: 'a> Visitor<'tcx> for TypeComplexityVisitor<'a, 'tcx> { + fn visit_ty(&mut self, ty: &'tcx Ty) { let (add_score, sub_nest) = match ty.node { // _, &x and *x have only small overhead; don't mess with nesting level TyInfer | TyPtr(..) | TyRptr(..) => (1, 0), // the "normal" components of a type: named types, arrays/tuples - TyPath(..) | - TySlice(..) | - TyTup(..) | - TyArray(..) => (10 * self.nest, 1), + TyPath(..) | TySlice(..) | TyTup(..) | TyArray(..) => (10 * self.nest, 1), // "Sum" of trait bounds TyObjectSum(..) => (20 * self.nest, 0), @@ -645,6 +713,9 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { walk_ty(self, ty); self.nest -= sub_nest; } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } /// **What it does:** Checks for expressions where a character literal is cast @@ -676,8 +747,8 @@ impl LintPass for CharLitAsU8 { } } -impl LateLintPass for CharLitAsU8 { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { use syntax::ast::{LitKind, UintTy}; if let ExprCast(ref e, _) = expr.node { @@ -687,9 +758,7 @@ impl LateLintPass for CharLitAsU8 { let msg = "casting character literal to u8. `char`s \ are 4 bytes wide in rust, so casting to u8 \ truncates them"; - let help = format!("Consider using a byte literal \ - instead:\nb{}", - snippet(cx, e.span, "'x'")); + let help = format!("Consider using a byte literal instead:\nb{}", snippet(cx, e.span, "'x'")); span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); } } @@ -746,12 +815,15 @@ enum AbsurdComparisonResult { -fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) - -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { +fn detect_absurd_comparison<'a>( + cx: &LateContext, + op: BinOp_, + lhs: &'a Expr, + rhs: &'a Expr +) -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { use types::ExtremeType::*; use types::AbsurdComparisonResult::*; use utils::comparisons::*; - type Extr<'a> = ExtremeExpr<'a>; let normalized = normalize_comparison(op, lhs, rhs); let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { @@ -766,20 +838,20 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs Some(match rel { Rel::Lt => { match (lx, rx) { - (Some(l @ Extr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x - (_, Some(r @ Extr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min + (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x + (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min _ => return None, } - } + }, Rel::Le => { match (lx, rx) { - (Some(l @ Extr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x - (Some(l @ Extr { which: Maximum, .. }), _) => (l, InequalityImpossible), //max <= x - (_, Some(r @ Extr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min - (_, Some(r @ Extr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max + (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x + (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), //max <= x + (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min + (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max _ => return None, } - } + }, Rel::Ne | Rel::Eq => return None, }) } @@ -840,8 +912,8 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { use types::ExtremeType::*; use types::AbsurdComparisonResult::*; @@ -859,7 +931,7 @@ impl LateLintPass for AbsurdExtremeComparisons { instead", snippet(cx, lhs.span, "lhs"), snippet(cx, rhs.span, "rhs")) - } + }, }; let help = format!("because {} is the {} value for this type, {}", @@ -962,7 +1034,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)), IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)), }) - } + }, TyUint(uint_ty) => { Some(match uint_ty { UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)), @@ -971,7 +1043,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)), UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)), }) - } + }, _ => None, } } else { @@ -996,7 +1068,7 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option { } else { None } - } + }, Err(_) => None, } } @@ -1014,8 +1086,15 @@ fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: boo } } -fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons::Rel, - lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, invert: bool) { +fn upcast_comparison_bounds_err( + cx: &LateContext, + span: &Span, + rel: comparisons::Rel, + lhs_bounds: Option<(FullInt, FullInt)>, + lhs: &Expr, + rhs: &Expr, + invert: bool +) { use utils::comparisons::*; if let Some((lb, ub)) = lhs_bounds { @@ -1031,14 +1110,14 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: } else { ub < norm_rhs_val } - } + }, Rel::Le => { if invert { norm_rhs_val <= lb } else { ub <= norm_rhs_val } - } + }, Rel::Eq | Rel::Ne => unreachable!(), } { err_upcast_comparison(cx, span, lhs, true) @@ -1049,14 +1128,14 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: } else { lb >= norm_rhs_val } - } + }, Rel::Le => { if invert { norm_rhs_val > ub } else { lb > norm_rhs_val } - } + }, Rel::Eq | Rel::Ne => unreachable!(), } { err_upcast_comparison(cx, span, lhs, false) @@ -1065,8 +1144,8 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: } } -impl LateLintPass for InvalidUpcastComparisons { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidUpcastComparisons { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index afe519893a9f..1d5ab7db3461 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -68,8 +68,8 @@ impl LintPass for Unicode { } } -impl LateLintPass for Unicode { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unicode { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprLit(ref lit) = expr.node { if let LitKind::Str(_, _) = lit.node { check_str(cx, lit.span) diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 7cd108dd02d9..07afc55ae7f1 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,6 +1,5 @@ -use rustc::hir::*; use rustc::lint::*; -use syntax::ast::Name; +use syntax::ast::*; use syntax::codemap::Span; use syntax::symbol::InternedString; use utils::span_lint; @@ -34,20 +33,19 @@ impl LintPass for UnsafeNameRemoval { } } -impl LateLintPass for UnsafeNameRemoval { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemUse(ref item_use) = item.node { +impl EarlyLintPass for UnsafeNameRemoval { + fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + if let ItemKind::Use(ref item_use) = item.node { match item_use.node { ViewPath_::ViewPathSimple(ref name, ref path) => { - unsafe_to_safe_check( - path.segments - .last() - .expect("use paths cannot be empty") - .name, - *name, - cx, &item.span - ); - } + unsafe_to_safe_check(path.segments + .last() + .expect("use paths cannot be empty") + .identifier, + *name, + cx, + &item.span); + }, ViewPath_::ViewPathList(_, ref path_list_items) => { for path_list_item in path_list_items.iter() { let plid = path_list_item.node; @@ -55,25 +53,21 @@ impl LateLintPass for UnsafeNameRemoval { unsafe_to_safe_check(plid.name, rename, cx, &item.span); }; } - } - ViewPath_::ViewPathGlob(_) => {} + }, + ViewPath_::ViewPathGlob(_) => {}, } } } } -fn unsafe_to_safe_check(old_name: Name, new_name: Name, cx: &LateContext, span: &Span) { - let old_str = old_name.as_str(); - let new_str = new_name.as_str(); +fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext, span: &Span) { + let old_str = old_name.name.as_str(); + let new_str = new_name.name.as_str(); if contains_unsafe(&old_str) && !contains_unsafe(&new_str) { span_lint(cx, UNSAFE_REMOVED_FROM_NAME, *span, - &format!( - "removed \"unsafe\" from the name of `{}` in use as `{}`", - old_str, - new_str - )); + &format!("removed \"unsafe\" from the name of `{}` in use as `{}`", old_str, new_str)); } } diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index e76b9b697084..9017fd6933e8 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir; -use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; +use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, NestedVisitorMap}; use std::collections::HashMap; use syntax::ast; use syntax::codemap::Span; @@ -29,15 +29,9 @@ declare_lint! { pub struct UnusedLabel; -#[derive(Default)] -struct UnusedLabelVisitor { +struct UnusedLabelVisitor<'a, 'tcx: 'a> { labels: HashMap, -} - -impl UnusedLabelVisitor { - pub fn new() -> UnusedLabelVisitor { - ::std::default::Default::default() - } + cx: &'a LateContext<'a, 'tcx>, } impl LintPass for UnusedLabel { @@ -46,14 +40,25 @@ impl LintPass for UnusedLabel { } } -impl LateLintPass for UnusedLabel { - fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Expr, span: Span, fn_id: ast::NodeId) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Expr, + span: Span, + fn_id: ast::NodeId + ) { if in_macro(cx, span) { return; } - let mut v = UnusedLabelVisitor::new(); - walk_fn(&mut v, kind, decl, body, span, fn_id); + let mut v = UnusedLabelVisitor { + cx: cx, + labels: HashMap::new(), + }; + walk_fn(&mut v, kind, decl, body.expr_id(), span, fn_id); for (label, span) in v.labels { span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); @@ -61,20 +66,23 @@ impl LateLintPass for UnusedLabel { } } -impl<'v> Visitor<'v> for UnusedLabelVisitor { - fn visit_expr(&mut self, expr: &hir::Expr) { +impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprBreak(Some(label), _) | hir::ExprAgain(Some(label)) => { - self.labels.remove(&label.node.as_str()); - } + self.labels.remove(&label.name.as_str()); + }, hir::ExprLoop(_, Some(label), _) | hir::ExprWhile(_, _, Some(label)) => { self.labels.insert(label.node.as_str(), expr.span); - } + }, _ => (), } walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index a277226eb67c..f973c2afd27a 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -18,8 +18,7 @@ pub enum Rel { } /// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`. -pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) - -> Option<(Rel, &'a Expr, &'a Expr)> { +pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(Rel, &'a Expr, &'a Expr)> { match op { BinOp_::BiLt => Some((Rel::Lt, lhs, rhs)), BinOp_::BiLe => Some((Rel::Le, lhs, rhs)), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 9a1753d511ce..d80fa17e29f7 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -8,21 +8,20 @@ use syntax::{ast, codemap}; use toml; /// Get the configuration file from arguments. -pub fn file_from_args(args: &[codemap::Spanned]) -> Result, (&'static str, codemap::Span)> { +pub fn file_from_args(args: &[codemap::Spanned]) + -> Result, (&'static str, codemap::Span)> { for arg in args.iter().filter_map(|a| a.meta_item()) { if arg.name() == "conf_file" { return match arg.node { ast::MetaItemKind::Word | - ast::MetaItemKind::List(_) => { - Err(("`conf_file` must be a named value", arg.span)) - } + ast::MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)), ast::MetaItemKind::NameValue(ref value) => { if let ast::LitKind::Str(ref file, _) = value.node { Ok(Some(file.to_string().into())) } else { Err(("`conf_file` value must be a string", value.span)) } - } + }, }; } } @@ -38,14 +37,12 @@ pub enum Error { /// The file is not valid TOML. Toml(Vec), /// Type error. - Type( - /// The name of the key. - &'static str, - /// The expected type. - &'static str, - /// The type we got instead. - &'static str - ), + Type(/// The name of the key. + &'static str, + /// The expected type. + &'static str, + /// The type we got instead. + &'static str), /// There is an unknown key is the file. UnknownKey(String), } @@ -66,10 +63,10 @@ impl fmt::Display for Error { } Ok(()) - } + }, Error::Type(key, expected, got) => { write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) - } + }, Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), } } @@ -134,7 +131,12 @@ macro_rules! define_Conf { // how to read the value? (CONV i64, $value: expr) => { $value.as_integer() }; - (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() }; + (CONV u64, $value: expr) => { + $value.as_integer() + .iter() + .filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }) + .next() + }; (CONV String, $value: expr) => { $value.as_str().map(Into::into) }; (CONV Vec, $value: expr) => {{ let slice = $value.as_slice(); @@ -142,12 +144,10 @@ macro_rules! define_Conf { if let Some(slice) = slice { if slice.iter().any(|v| v.as_str().is_none()) { None + } else { + Some(slice.iter().map(|v| v.as_str().expect("already checked").to_owned()).collect()) } - else { - Some(slice.iter().map(|v| v.as_str().unwrap_or_else(|| unreachable!()).to_owned()).collect()) - } - } - else { + } else { None } }}; @@ -163,7 +163,19 @@ define_Conf! { /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks - ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "GPLv2", "GPLv3", "GitHub", "IPv4", "IPv6", "JavaScript", "NaN", "OAuth", "OpenGL", "TrueType", "iOS", "macOS"] => Vec), + ("doc-valid-idents", doc_valid_idents, [ + "MiB", "GiB", "TiB", "PiB", "EiB", + "DirectX", + "GPLv2", "GPLv3", + "GitHub", + "IPv4", "IPv6", + "JavaScript", + "NaN", + "OAuth", + "OpenGL", + "TrueType", + "iOS", "macOS", + ] => Vec), /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64), /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have @@ -196,7 +208,7 @@ pub fn lookup_conf_file() -> io::Result> { if e.kind() != io::ErrorKind::NotFound { return Err(e); } - } + }, _ => (), } } @@ -231,11 +243,11 @@ pub fn read(path: Option<&path::Path>) -> (Conf, Vec) { } buf - } + }, Err(err) => { errors.push(err.into()); return (conf, errors); - } + }, }; let mut parser = toml::Parser::new(&file); diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs index 179c251e3228..87008307c5f6 100644 --- a/clippy_lints/src/utils/constants.rs +++ b/clippy_lints/src/utils/constants.rs @@ -7,15 +7,5 @@ /// See also [the reference][reference-types] for a list of such types. /// /// [reference-types]: https://doc.rust-lang.org/reference.html#types -pub const BUILTIN_TYPES: &'static [&'static str] = &[ - "i8", "u8", - "i16", "u16", - "i32", "u32", - "i64", "u64", - "isize", "usize", - "f32", - "f64", - "bool", - "str", - "char", -]; +pub const BUILTIN_TYPES: &'static [&'static str] = &["i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "isize", + "usize", "f32", "f64", "bool", "str", "char"]; diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 26b45009a825..c83dae26fdaa 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -44,34 +44,21 @@ pub struct Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. pub fn range(expr: &hir::Expr) -> Option { - /// Skip unstable blocks. To be removed when ranges get stable. - fn unwrap_unstable(expr: &hir::Expr) -> &hir::Expr { - if let hir::ExprBlock(ref block) = expr.node { - if block.rules == hir::BlockCheckMode::PushUnstableBlock || block.rules == hir::BlockCheckMode::PopUnstableBlock { - if let Some(ref expr) = block.expr { - return expr; - } - } - } - - expr - } - /// Find the field named `name` in the field. Always return `Some` for convenience. fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> { let expr = &fields.iter() - .find(|field| field.name.node == name) - .unwrap_or_else(|| panic!("missing {} field for range", name)) - .expr; + .find(|field| field.name.node == name) + .unwrap_or_else(|| panic!("missing {} field for range", name)) + .expr; - Some(unwrap_unstable(expr)) + Some(expr) } // The range syntax is expanded to literal paths starting with `core` or `std` depending on // `#[no_std]`. Testing both instead of resolving the paths. - match unwrap_unstable(expr).node { - hir::ExprPath(None, ref path) => { + match expr.node { + hir::ExprPath(ref path) => { if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) { Some(Range { start: None, @@ -81,7 +68,7 @@ pub fn range(expr: &hir::Expr) -> Option { } else { None } - } + }, hir::ExprStruct(ref path, ref fields, None) => { if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) { Some(Range { @@ -90,7 +77,7 @@ pub fn range(expr: &hir::Expr) -> Option { limits: ast::RangeLimits::HalfOpen, }) } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || - match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { + match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { Some(Range { start: get_field("start", fields), end: get_field("end", fields), @@ -117,7 +104,7 @@ pub fn range(expr: &hir::Expr) -> Option { } else { None } - } + }, _ => None, } } @@ -168,15 +155,15 @@ pub enum VecArgs<'a> { pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option> { if_let_chain!{[ let hir::ExprCall(ref fun, ref args) = expr.node, - let hir::ExprPath(_, ref path) = fun.node, - let Some(fun_def) = resolve_node(cx, fun.id), + let hir::ExprPath(ref path) = fun.node, is_expn_of(cx, fun.span, "vec").is_some(), ], { + let fun_def = resolve_node(cx, path, fun.id); return if match_def_path(cx, fun_def.def_id(), &paths::VEC_FROM_ELEM) && args.len() == 2 { // `vec![elem; size]` case Some(VecArgs::Repeat(&args[0], &args[1])) } - else if match_path(path, &["into_vec"]) && args.len() == 1 { + else if match_def_path(cx, fun_def.def_id(), &paths::SLICE_INTO_VEC) && args.len() == 1 { // `vec![a, b, c]` case if_let_chain!{[ let hir::ExprBox(ref boxed) = args[0].node, diff --git a/clippy_lints/src/utils/hir.rs b/clippy_lints/src/utils/hir.rs index 1199f87ae3c5..80399825b6d1 100644 --- a/clippy_lints/src/utils/hir.rs +++ b/clippy_lints/src/utils/hir.rs @@ -38,12 +38,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.node, &right.node) { (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { - both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && - both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) + both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) } else { false } - } + }, (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), _ => false, @@ -69,69 +68,64 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.node, &right.node) { (&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re), - (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()), + (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str()), (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr), (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => { lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - } + }, (&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r), (&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) - } - (&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => - both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()) - && both(le, re, |l, r| self.eq_expr(l, r)), + }, + (&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => { + both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str()) && both(le, re, |l, r| self.eq_expr(l, r)) + }, (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), (&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => { !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) - } + }, (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) | - (&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => { - self.eq_expr(lx, rx) && self.eq_ty(lt, rt) - } + (&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt), (&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => { l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp) - } + }, (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => { self.eq_expr(lc, rc) && self.eq_block(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r)) - } + }, (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprLoop(ref lb, ref ll, ref lls), &ExprLoop(ref rb, ref rl, ref rls)) => { - self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) && lls == rls - } + lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) + }, (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { ls == rs && self.eq_expr(le, re) && over(la, ra, |l, r| { self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) && over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r)) }) - } + }, (&ExprMethodCall(ref l_name, ref l_tys, ref l_args), &ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => { - !self.ignore_fn && l_name.node == r_name.node && - over(l_tys, r_tys, |l, r| self.eq_ty(l, r)) && + !self.ignore_fn && l_name.node == r_name.node && over(l_tys, r_tys, |l, r| self.eq_ty(l, r)) && self.eq_exprs(l_args, r_args) - } + }, (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl), (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), - (&ExprPath(ref l_qself, ref l_subpath), &ExprPath(ref r_qself, ref r_subpath)) => { - both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath) - } + (&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r), (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => { - self.eq_path(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) && + self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) && over(lf, rf, |l, r| self.eq_field(l, r)) - } + }, (&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup), (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re), (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), (&ExprArray(ref l), &ExprArray(ref r)) => self.eq_exprs(l, r), (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => { self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) - } + }, _ => false, } } @@ -153,34 +147,43 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.node, &right.node) { (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => { - self.eq_path(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs - } - (&PatKind::Binding(ref lb, ref li, ref lp), &PatKind::Binding(ref rb, ref ri, ref rp)) => { + self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs + }, + (&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => { lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) - } - (&PatKind::Path(ref ql, ref l), &PatKind::Path(ref qr, ref r)) => { - both(ql, qr, |ql, qr| self.eq_qself(ql, qr)) && self.eq_path(l, r) - } + }, + (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r), (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => { ls == rs && over(l, r, |l, r| self.eq_pat(l, r)) - } + }, (&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => { self.eq_expr(ls, rs) && self.eq_expr(le, re) - } + }, (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re), (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => { over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) && both(li, ri, |l, r| self.eq_pat(l, r)) - } + }, (&PatKind::Wild, &PatKind::Wild) => true, _ => false, } } + fn eq_qpath(&self, left: &QPath, right: &QPath) -> bool { + match (left, right) { + (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => { + both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath) + }, + (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => { + self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg) + }, + _ => false, + } + } + fn eq_path(&self, left: &Path, right: &Path) -> bool { - left.global == right.global && - over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) + left.global == right.global && over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) } fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool { @@ -189,42 +192,31 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) && over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r)) - } + }, (&ParenthesizedParameters(ref left), &ParenthesizedParameters(ref right)) => { over(&left.inputs, &right.inputs, |l, r| self.eq_ty(l, r)) && both(&left.output, &right.output, |l, r| self.eq_ty(l, r)) - } + }, (&AngleBracketedParameters(_), &ParenthesizedParameters(_)) | - (&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => { - false - } + (&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => false, } } fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool { // The == of idents doesn't work with different contexts, // we have to be explicit about hygiene - left.name.as_str() == right.name.as_str() && - self.eq_path_parameters(&left.parameters, &right.parameters) - } - - fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool { - left.ty.node == right.ty.node && left.position == right.position + left.name.as_str() == right.name.as_str() && self.eq_path_parameters(&left.parameters, &right.parameters) } fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { match (&left.node, &right.node) { (&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyArray(ref lt, ref ll), &TyArray(ref rt, ref rl)) => { - self.eq_ty(lt, rt) && self.eq_expr(ll, rl) - } + (&TyArray(ref lt, ref ll), &TyArray(ref rt, ref rl)) => self.eq_ty(lt, rt) && self.eq_expr(ll, rl), (&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)) => { l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty) - } - (&TyPath(ref lq, ref l_path), &TyPath(ref rq, ref r_path)) => { - both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(l_path, r_path) - } + }, + (&TyPath(ref l), &TyPath(ref r)) => self.eq_qpath(l, r), (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyInfer, &TyInfer) => true, _ => false, @@ -238,13 +230,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_, &'a Expr, &'a Expr)> { match binop { - BiAdd | - BiMul | - BiBitXor | - BiBitAnd | - BiEq | - BiNe | - BiBitOr => Some((binop, rhs, lhs)), + BiAdd | BiMul | BiBitXor | BiBitAnd | BiEq | BiNe | BiBitOr => Some((binop, rhs, lhs)), BiLt => Some((BiGt, rhs, lhs)), BiLe => Some((BiGe, rhs, lhs)), BiGe => Some((BiLe, rhs, lhs)), @@ -313,88 +299,88 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { c.hash(&mut self.s); m.hash(&mut self.s); self.hash_expr(e); - } + }, ExprAgain(i) => { let c: fn(_) -> _ = ExprAgain; c.hash(&mut self.s); if let Some(i) = i { - self.hash_name(&i.node); + self.hash_name(&i.name); } - } + }, ExprAssign(ref l, ref r) => { let c: fn(_, _) -> _ = ExprAssign; c.hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); - } + }, ExprAssignOp(ref o, ref l, ref r) => { let c: fn(_, _, _) -> _ = ExprAssignOp; c.hash(&mut self.s); o.hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); - } + }, ExprBlock(ref b) => { let c: fn(_) -> _ = ExprBlock; c.hash(&mut self.s); self.hash_block(b); - } + }, ExprBinary(op, ref l, ref r) => { let c: fn(_, _, _) -> _ = ExprBinary; c.hash(&mut self.s); op.node.hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); - } + }, ExprBreak(i, ref j) => { let c: fn(_, _) -> _ = ExprBreak; c.hash(&mut self.s); if let Some(i) = i { - self.hash_name(&i.node); + self.hash_name(&i.name); } if let Some(ref j) = *j { self.hash_expr(&*j); } - } + }, ExprBox(ref e) => { let c: fn(_) -> _ = ExprBox; c.hash(&mut self.s); self.hash_expr(e); - } + }, ExprCall(ref fun, ref args) => { let c: fn(_, _) -> _ = ExprCall; c.hash(&mut self.s); self.hash_expr(fun); self.hash_exprs(args); - } + }, ExprCast(ref e, ref _ty) => { let c: fn(_, _) -> _ = ExprCast; c.hash(&mut self.s); self.hash_expr(e); // TODO: _ty - } - ExprClosure(cap, _, ref e, _) => { + }, + ExprClosure(cap, _, eid, _) => { let c: fn(_, _, _, _) -> _ = ExprClosure; c.hash(&mut self.s); cap.hash(&mut self.s); - self.hash_expr(e); - } + self.hash_expr(self.cx.tcx.map.expr(eid)); + }, ExprField(ref e, ref f) => { let c: fn(_, _) -> _ = ExprField; c.hash(&mut self.s); self.hash_expr(e); self.hash_name(&f.node); - } + }, ExprIndex(ref a, ref i) => { let c: fn(_, _) -> _ = ExprIndex; c.hash(&mut self.s); self.hash_expr(a); self.hash_expr(i); - } + }, ExprInlineAsm(..) => { let c: fn(_, _, _) -> _ = ExprInlineAsm; c.hash(&mut self.s); - } + }, ExprIf(ref cond, ref t, ref e) => { let c: fn(_, _, _) -> _ = ExprIf; c.hash(&mut self.s); @@ -403,21 +389,20 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { if let Some(ref e) = *e { self.hash_expr(e); } - } + }, ExprLit(ref l) => { let c: fn(_) -> _ = ExprLit; c.hash(&mut self.s); l.hash(&mut self.s); - } - ExprLoop(ref b, ref i, ref j) => { + }, + ExprLoop(ref b, ref i, _) => { let c: fn(_, _, _) -> _ = ExprLoop; c.hash(&mut self.s); self.hash_block(b); if let Some(i) = *i { self.hash_name(&i.node); } - j.hash(&mut self.s); - } + }, ExprMatch(ref e, ref arms, ref s) => { let c: fn(_, _, _) -> _ = ExprMatch; c.hash(&mut self.s); @@ -432,36 +417,36 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { } s.hash(&mut self.s); - } + }, ExprMethodCall(ref name, ref _tys, ref args) => { let c: fn(_, _, _) -> _ = ExprMethodCall; c.hash(&mut self.s); self.hash_name(&name.node); self.hash_exprs(args); - } + }, ExprRepeat(ref e, ref l) => { let c: fn(_, _) -> _ = ExprRepeat; c.hash(&mut self.s); self.hash_expr(e); self.hash_expr(l); - } + }, ExprRet(ref e) => { let c: fn(_) -> _ = ExprRet; c.hash(&mut self.s); if let Some(ref e) = *e { self.hash_expr(e); } - } - ExprPath(ref _qself, ref subpath) => { - let c: fn(_, _) -> _ = ExprPath; + }, + ExprPath(ref qpath) => { + let c: fn(_) -> _ = ExprPath; c.hash(&mut self.s); - self.hash_path(subpath); - } + self.hash_qpath(qpath); + }, ExprStruct(ref path, ref fields, ref expr) => { let c: fn(_, _, _) -> _ = ExprStruct; c.hash(&mut self.s); - self.hash_path(path); + self.hash_qpath(path); for f in fields { self.hash_name(&f.name.node); @@ -471,38 +456,38 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { if let Some(ref e) = *expr { self.hash_expr(e); } - } + }, ExprTup(ref tup) => { let c: fn(_) -> _ = ExprTup; c.hash(&mut self.s); self.hash_exprs(tup); - } + }, ExprTupField(ref le, li) => { let c: fn(_, _) -> _ = ExprTupField; c.hash(&mut self.s); self.hash_expr(le); li.node.hash(&mut self.s); - } + }, ExprType(ref e, ref _ty) => { let c: fn(_, _) -> _ = ExprType; c.hash(&mut self.s); self.hash_expr(e); // TODO: _ty - } + }, ExprUnary(lop, ref le) => { let c: fn(_, _) -> _ = ExprUnary; c.hash(&mut self.s); lop.hash(&mut self.s); self.hash_expr(le); - } + }, ExprArray(ref v) => { let c: fn(_) -> _ = ExprArray; c.hash(&mut self.s); self.hash_exprs(v); - } + }, ExprWhile(ref cond, ref b, l) => { let c: fn(_, _, _) -> _ = ExprWhile; c.hash(&mut self.s); @@ -512,7 +497,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { if let Some(l) = l { self.hash_name(&l.node); } - } + }, } } @@ -526,6 +511,18 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { n.as_str().hash(&mut self.s); } + pub fn hash_qpath(&mut self, p: &QPath) { + match *p { + QPath::Resolved(_, ref path) => { + self.hash_path(path); + }, + QPath::TypeRelative(_, ref path) => { + self.hash_name(&path.name); + }, + } + // self.cx.tcx.tables().qpath_def(p, id).hash(&mut self.s); + } + pub fn hash_path(&mut self, p: &Path) { p.global.hash(&mut self.s); for p in &p.segments { @@ -544,17 +541,17 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { self.hash_expr(init); } } - } + }, StmtExpr(ref expr, _) => { let c: fn(_, _) -> _ = StmtExpr; c.hash(&mut self.s); self.hash_expr(expr); - } + }, StmtSemi(ref expr, _) => { let c: fn(_, _) -> _ = StmtSemi; c.hash(&mut self.s); self.hash_expr(expr); - } + }, } } } diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 70f47abb54f3..79cf15b6c5f5 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -36,15 +36,15 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if !has_attr(&item.attrs) { return; } print_item(cx, item); } - fn check_impl_item(&mut self, cx: &LateContext, item: &hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) { if !has_attr(&item.attrs) { return; } @@ -67,34 +67,34 @@ impl LateLintPass for Pass { hir::ImplItemKind::Type(_) => println!("associated type"), } } -/* - fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { - if !has_attr(&item.attrs) { - return; - } - } + // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { + // if !has_attr(&item.attrs) { + // return; + // } + // } + // + // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: + // &hir::Generics) { + // if !has_attr(&var.node.attrs) { + // return; + // } + // } + // + // fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) { + // if !has_attr(&field.attrs) { + // return; + // } + // } + // - fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant, _: &hir::Generics) { - if !has_attr(&var.node.attrs) { - return; - } - } - - fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) { - if !has_attr(&field.attrs) { - return; - } - } -*/ - - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { if !has_attr(&expr.attrs) { return; } print_expr(cx, expr, 0); } - fn check_arm(&mut self, cx: &LateContext, arm: &hir::Arm) { + fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) { if !has_attr(&arm.attrs) { return; } @@ -109,23 +109,22 @@ impl LateLintPass for Pass { print_expr(cx, &arm.body, 1); } - fn check_stmt(&mut self, cx: &LateContext, stmt: &hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) { if !has_attr(stmt.node.attrs()) { return; } match stmt.node { hir::StmtDecl(ref decl, _) => print_decl(cx, decl), - hir::StmtExpr(ref e, _) | hir::StmtSemi(ref e, _) => print_expr(cx, e, 0), + hir::StmtExpr(ref e, _) | + hir::StmtSemi(ref e, _) => print_expr(cx, e, 0), } } -/* - - fn check_foreign_item(&mut self, cx: &LateContext, item: &hir::ForeignItem) { - if !has_attr(&item.attrs) { - return; - } - } -*/ + // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) { + // if !has_attr(&item.attrs) { + // return; + // } + // } + // } fn has_attr(attrs: &[Attribute]) -> bool { @@ -275,11 +274,14 @@ fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) { println!("{}index expr:", ind); print_expr(cx, idx, indent + 1); }, - hir::ExprPath(ref sel, ref path) => { - println!("{}Path, {}", ind, ty); - println!("{}self: {:?}", ind, sel); + hir::ExprPath(hir::QPath::Resolved(ref ty, ref path)) => { + println!("{}Resolved Path, {:?}", ind, ty); println!("{}path: {:?}", ind, path); }, + hir::ExprPath(hir::QPath::TypeRelative(ref ty, ref seg)) => { + println!("{}Relative Path, {:?}", ind, ty); + println!("{}seg: {:?}", ind, seg); + }, hir::ExprAddrOf(ref muta, ref e) => { println!("{}AddrOf, {}", ind, ty); println!("mutability: {:?}", muta); @@ -353,8 +355,8 @@ fn print_item(cx: &LateContext, item: &hir::Item) { } else { println!("weird extern crate without a crate id"); } - } - hir::ItemUse(ref path) => println!("{:?}", path.node), + }, + hir::ItemUse(ref path, ref kind) => println!("{:?}, {:?}", path, kind), hir::ItemStatic(..) => println!("static item of type {:#?}", cx.tcx.item_type(did)), hir::ItemConst(..) => println!("const item of type {:#?}", cx.tcx.item_type(did)), hir::ItemFn(..) => { @@ -383,13 +385,11 @@ fn print_item(cx: &LateContext, item: &hir::Item) { println!("trait has no default impl"); } }, - hir::ItemDefaultImpl(_, ref trait_ref) => { - let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id(); - println!("default impl for `{}`", cx.tcx.item_path_str(trait_did)); + hir::ItemDefaultImpl(_, ref _trait_ref) => { + println!("default impl"); }, - hir::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { - let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id(); - println!("impl of trait `{}`", cx.tcx.item_path_str(trait_did)); + hir::ItemImpl(_, _, _, Some(ref _trait_ref), _, _) => { + println!("trait impl"); }, hir::ItemImpl(_, _, _, None, _, _) => { println!("impl"); @@ -402,7 +402,7 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) { println!("{}+", ind); match pat.node { hir::PatKind::Wild => println!("{}Wild", ind), - hir::PatKind::Binding(ref mode, ref name, ref inner) => { + hir::PatKind::Binding(ref mode, _, ref name, ref inner) => { println!("{}Binding", ind); println!("{}mode: {:?}", ind, mode); println!("{}name: {}", ind, name.node); @@ -434,11 +434,14 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) { print_pat(cx, field, indent + 1); } }, - hir::PatKind::Path(ref sel, ref path) => { - println!("{}Path", ind); - println!("{}self: {:?}", ind, sel); + hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => { + println!("{}Resolved Path, {:?}", ind, ty); println!("{}path: {:?}", ind, path); }, + hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => { + println!("{}Relative Path, {:?}", ind, ty); + println!("{}seg: {:?}", ind, seg); + }, hir::PatKind::Tuple(ref pats, opt_dots_position) => { println!("{}Tuple", ind); if let Some(dot_position) = opt_dots_position { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 93d1ce8629b0..cf9e90d62bd4 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr}; +use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; use utils::{paths, match_path, span_lint}; use syntax::symbol::InternedString; use syntax::ast::{Name, NodeId, ItemKind, Crate as AstCrate}; @@ -75,8 +75,8 @@ impl EarlyLintPass for Clippy { span_lint(cx, CLIPPY_LINTS_INTERNAL, item.span, - "this constant should be before the previous constant due to lexical ordering", - ); + "this constant should be before the previous constant due to lexical \ + ordering"); } } last_name = Some(name); @@ -104,19 +104,22 @@ impl LintPass for LintWithoutLintPass { } -impl LateLintPass for LintWithoutLintPass { - fn check_item(&mut self, _: &LateContext, item: &Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if let ItemStatic(ref ty, MutImmutable, ref expr) = item.node { if is_lint_ref_type(ty) { self.declared_lints.insert(item.name, item.span); } else if is_lint_array_type(ty) && item.vis == Visibility::Inherited && item.name == "ARRAY" { - let mut collector = LintCollector { output: &mut self.registered_lints }; + let mut collector = LintCollector { + output: &mut self.registered_lints, + cx: cx, + }; collector.visit_expr(expr); } } } - fn check_crate_post(&mut self, cx: &LateContext, _: &Crate) { + fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, _: &'tcx Crate) { for (lint_name, &lint_span) in &self.declared_lints { // When using the `declare_lint!` macro, the original `lint_span`'s // file points to "". @@ -140,7 +143,7 @@ impl LateLintPass for LintWithoutLintPass { fn is_lint_ref_type(ty: &Ty) -> bool { if let TyRptr(Some(_), MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node { - if let TyPath(None, ref path) = inner.node { + if let TyPath(ref path) = inner.node { return match_path(path, &paths::LINT); } } @@ -149,25 +152,29 @@ fn is_lint_ref_type(ty: &Ty) -> bool { fn is_lint_array_type(ty: &Ty) -> bool { - if let TyPath(None, ref path) = ty.node { + if let TyPath(ref path) = ty.node { match_path(path, &paths::LINT_ARRAY) } else { false } } -struct LintCollector<'a> { +struct LintCollector<'a, 'tcx: 'a> { output: &'a mut HashSet, + cx: &'a LateContext<'a, 'tcx>, } -impl<'v, 'a: 'v> Visitor<'v> for LintCollector<'a> { - fn visit_expr(&mut self, expr: &'v Expr) { +impl<'a, 'tcx: 'a> Visitor<'tcx> for LintCollector<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { walk_expr(self, expr); } - fn visit_path(&mut self, path: &'v Path, _: NodeId) { + fn visit_path(&mut self, path: &'tcx Path, _: NodeId) { if path.segments.len() == 1 { self.output.insert(path.segments[0].name); } } + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.map) + } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 47d693e03b2d..77b33d7b5893 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,6 +1,7 @@ use reexport::*; use rustc::hir::*; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::def::Def; use rustc::hir::map::Node; use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::session::Session; @@ -34,23 +35,27 @@ pub type MethodArgs = HirVec>; /// Produce a nested chain of if-lets and ifs from the patterns: /// -/// if_let_chain! {[ -/// let Some(y) = x, -/// y.len() == 2, -/// let Some(z) = y, -/// ], { -/// block -/// }} +/// ```rust,ignore +/// if_let_chain! {[ +/// let Some(y) = x, +/// y.len() == 2, +/// let Some(z) = y, +/// ], { +/// block +/// }} +/// ``` /// /// becomes /// -/// if let Some(y) = x { -/// if y.len() == 2 { -/// if let Some(z) = y { -/// block -/// } +/// ```rust,ignore +/// if let Some(y) = x { +/// if y.len() == 2 { +/// if let Some(z) = y { +/// block /// } /// } +/// } +/// ``` #[macro_export] macro_rules! if_let_chain { ([let $pat:pat = $expr:expr, $($tt:tt)+], $block:block) => { @@ -93,16 +98,27 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.expn_id != lhs.expn_id } /// Returns true if this `expn_info` was expanded by any macro. -pub fn in_macro(cx: &T, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) +pub fn in_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { + cx.sess().codemap().with_expn_info(span.expn_id, |info| { + match info { + Some(info) => { + match info.callee.format { + // don't treat range expressions desugared to structs as "in_macro" + ExpnFormat::CompilerDesugaring(name) => name != "...", + _ => true, + } + }, + None => false, + } + }) } /// Returns true if the macro that expanded the crate was outside of the current crate or was a /// compiler plugin. -pub fn in_external_macro(cx: &T, span: Span) -> bool { +pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { /// Invokes `in_macro` with the expansion info of the given span slightly heavy, try to use /// this after other checks have already happened. - fn in_macro_ext(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { + fn in_macro_ext<'a, T: LintContext<'a>>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { if let ExpnFormat::MacroAttribute(..) = info.callee.format { @@ -123,7 +139,7 @@ pub fn in_external_macro(cx: &T, span: Span) -> bool { /// Check if a `DefId`'s path matches the given absolute type path usage. /// /// # Examples -/// ``` +/// ```rust,ignore /// match_def_path(cx, id, &["core", "option", "Option"]) /// ``` /// @@ -150,8 +166,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { cx.tcx.push_item_path(&mut apb, def_id); - apb.names.len() == path.len() && - apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b) + apb.names.len() == path.len() && apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b) } /// Check if type is struct, enum or union type with given def path. @@ -167,11 +182,11 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); let trt_id = cx.tcx - .tables - .borrow() - .method_map - .get(&method_call) - .and_then(|callee| cx.tcx.impl_of_method(callee.def_id)); + .tables + .borrow() + .method_map + .get(&method_call) + .and_then(|callee| cx.tcx.impl_of_method(callee.def_id)); if let Some(trt_id) = trt_id { match_def_path(cx, trt_id, path) } else { @@ -184,11 +199,11 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool let method_call = ty::MethodCall::expr(expr.id); let trt_id = cx.tcx - .tables - .borrow() - .method_map - .get(&method_call) - .and_then(|callee| cx.tcx.trait_of_item(callee.def_id)); + .tables + .borrow() + .method_map + .get(&method_call) + .and_then(|callee| cx.tcx.trait_of_item(callee.def_id)); if let Some(trt_id) = trt_id { match_def_path(cx, trt_id, path) } else { @@ -196,20 +211,54 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool } } +pub fn last_path_segment(path: &QPath) -> &PathSegment { + match *path { + QPath::Resolved(_, ref path) => { + path.segments + .last() + .expect("A path must have at least one segment") + }, + QPath::TypeRelative(_, ref seg) => seg, + } +} + +pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> { + match *path { + QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]), + QPath::Resolved(..) => None, + QPath::TypeRelative(_, ref seg) => Some(seg), + } +} + /// Match a `Path` against a slice of segment string literals. /// /// # Examples -/// ``` +/// ```rust,ignore /// match_path(path, &["std", "rt", "begin_unwind"]) /// ``` -pub fn match_path(path: &Path, segments: &[&str]) -> bool { +pub fn match_path(path: &QPath, segments: &[&str]) -> bool { + match *path { + QPath::Resolved(_, ref path) => match_path_old(path, segments), + QPath::TypeRelative(ref ty, ref segment) => { + match ty.node { + TyPath(ref inner_path) => { + segments.len() > 0 && match_path(inner_path, &segments[..(segments.len() - 1)]) && + segment.name == segments[segments.len() - 1] + }, + _ => false, + } + }, + } +} + +pub fn match_path_old(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name == *b) } /// Match a `Path` against a slice of segment string literals, e.g. /// /// # Examples -/// ``` +/// ```rust,ignore /// match_path(path, &["std", "rt", "begin_unwind"]) /// ``` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { @@ -224,7 +273,10 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option { let crates = cstore.crates(); let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); if let Some(krate) = krate { - let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; let mut items = cstore.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -265,26 +317,25 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option { /// Check whether a type implements a trait. /// See also `get_trait_def_id`. -pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, - ty_params: Vec>) - -> bool { +pub fn implements_trait<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + ty: ty::Ty<'tcx>, + trait_id: DefId, + ty_params: Vec> +) -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let ty = cx.tcx.erase_regions(&ty); cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { - let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - &ty_params); + 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) }) } /// Resolve the definition of a node from its `NodeId`. -pub fn resolve_node(cx: &LateContext, id: NodeId) -> Option { - cx.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) +pub fn resolve_node(cx: &LateContext, qpath: &QPath, id: NodeId) -> def::Def { + cx.tcx.tables().qpath_def(qpath, id) } /// Match an `Expr` against a chain of methods, and return the matched `Expr`s. @@ -327,15 +378,15 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option { /// Convert a span to a code snippet if available, otherwise use default. /// /// # Example -/// ``` +/// ```rust,ignore /// snippet(cx, expr.span, "..") /// ``` -pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { +pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) } /// Convert a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt(cx: &T, span: Span) -> Option { +pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option { cx.sess().codemap().span_to_snippet(span).ok() } @@ -344,17 +395,22 @@ pub fn snippet_opt(cx: &T, span: Span) -> Option { /// things which need to be printed as such. /// /// # Example -/// ``` +/// ```rust,ignore /// snippet(cx, expr.span, "..") /// ``` -pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { +pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { let snip = snippet(cx, span, default); trim_multiline(snip, true) } /// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. /// Also takes an `Option` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option, default: &'a str) -> Cow<'a, str> { +pub fn expr_block<'a, 'b, T: LintContext<'b>>( + cx: &T, + expr: &Expr, + option: Option, + default: &'a str +) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.unwrap_or_default(); if let ExprBlock(_) = expr.node { @@ -375,32 +431,32 @@ pub fn trim_multiline(s: Cow, ignore_first: bool) -> Cow { fn trim_multiline_inner(s: Cow, ignore_first: bool, ch: char) -> Cow { let x = s.lines() - .skip(ignore_first as usize) - .filter_map(|l| { - if l.is_empty() { - None - } else { - // ignore empty lines - Some(l.char_indices() - .find(|&(_, x)| x != ch) - .unwrap_or((l.len(), ch)) - .0) - } - }) - .min() - .unwrap_or(0); + .skip(ignore_first as usize) + .filter_map(|l| { + if l.is_empty() { + None + } else { + // ignore empty lines + Some(l.char_indices() + .find(|&(_, x)| x != ch) + .unwrap_or((l.len(), ch)) + .0) + } + }) + .min() + .unwrap_or(0); if x > 0 { Cow::Owned(s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l - } else { - l.split_at(x).1 - } - }) - .collect::>() - .join("\n")) + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l + } else { + l.split_at(x).1 + } + }) + .collect::>() + .join("\n")) } else { s } @@ -423,19 +479,19 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { }) } -pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { +pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { let map = &cx.tcx.map; let enclosing_node = map.get_enclosing_scope(node) - .and_then(|enclosing_id| map.find(enclosing_id)); + .and_then(|enclosing_id| map.find(enclosing_id)); if let Some(node) = enclosing_node { match node { Node::NodeBlock(block) => Some(block), - Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref expr), .. }) => { - match expr.node { + Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, eid), .. }) => { + match cx.tcx.map.expr(eid).node { ExprBlock(ref block) => Some(block), _ => None, } - } + }, _ => None, } } else { @@ -455,20 +511,25 @@ impl<'a> DiagnosticWrapper<'a> { fn wiki_link(&mut self, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_WIKI_LINKS").is_err() { self.0.help(&format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + lint.name_lower())); } } } -pub fn span_lint(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { +pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { db.wiki_link(lint); } } -// FIXME: needless lifetime doesn't trigger here -pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) { +pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + help: &str +) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { db.0.help(help); @@ -476,8 +537,14 @@ pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp } } -pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, - note: &str) { +pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + note_span: Span, + note: &str +) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { if note_span == span { @@ -489,8 +556,13 @@ pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp } } -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) - where F: FnOnce(&mut DiagnosticBuilder<'a>) +pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>( + cx: &'a T, + lint: &'static Lint, + sp: Span, + msg: &str, + f: F +) where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { @@ -606,9 +678,9 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option { loop { let span_name_span = cx.tcx - .sess - .codemap() - .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site))); + .sess + .codemap() + .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site))); match span_name_span { Some((mac_name, new_span)) if mac_name == name => return Some(new_span), @@ -627,9 +699,9 @@ pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option /// `is_direct_expn_of`. pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option { let span_name_span = cx.tcx - .sess - .codemap() - .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site))); + .sess + .codemap() + .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site))); match span_name_span { Some((mac_name, new_span)) if mac_name == name => Some(new_span), @@ -663,11 +735,7 @@ pub fn camel_case_until(s: &str) -> usize { return i; } } - if up { - last_i - } else { - s.len() - } + if up { last_i } else { s.len() } } /// Return index of the last camel-case component of `s`. @@ -705,13 +773,18 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T let fn_def_id = cx.tcx.map.local_def_id(fn_item); let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig(); let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, fn_sig); - fn_sig.output + fn_sig.output() } /// Check if two types are the same. // 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: NodeId) -> bool { +pub fn same_tys<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + a: ty::Ty<'tcx>, + b: ty::Ty<'tcx>, + parameter_item: NodeId +) -> bool { let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item); cx.tcx.infer_ctxt(None, Some(parameter_env), Reveal::All).enter(|infcx| { let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs); @@ -736,37 +809,41 @@ pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, env: Node /// Return whether a pattern is refutable. pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool { - fn is_enum_variant(cx: &LateContext, did: NodeId) -> bool { - matches!(cx.tcx.def_map.borrow().get(&did).map(|d| d.full_def()), Some(def::Def::Variant(..)) | Some(def::Def::VariantCtor(..))) + fn is_enum_variant(cx: &LateContext, qpath: &QPath, did: NodeId) -> bool { + matches!(cx.tcx.tables().qpath_def(qpath, did), + def::Def::Variant(..) | def::Def::VariantCtor(..)) } - fn are_refutable<'a, I: Iterator>(cx: &LateContext, mut i: I) -> bool { + fn are_refutable<'a, I: Iterator>(cx: &LateContext, mut i: I) -> bool { i.any(|pat| is_refutable(cx, pat)) } match pat.node { - PatKind::Binding(..) | PatKind::Wild => false, - PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat), - PatKind::Lit(..) | PatKind::Range(..) => true, - PatKind::Path(..) => is_enum_variant(cx, pat.id), + PatKind::Binding(..) | + PatKind::Wild => false, + PatKind::Box(ref pat) | + PatKind::Ref(ref pat, _) => is_refutable(cx, pat), + PatKind::Lit(..) | + PatKind::Range(..) => true, + PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.id), PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), - PatKind::Struct(_, ref fields, _) => { - if is_enum_variant(cx, pat.id) { + PatKind::Struct(ref qpath, ref fields, _) => { + if is_enum_variant(cx, qpath, pat.id) { true } else { are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) } - } - PatKind::TupleStruct(_, ref pats, _) => { - if is_enum_variant(cx, pat.id) { + }, + PatKind::TupleStruct(ref qpath, ref pats, _) => { + if is_enum_variant(cx, qpath, pat.id) { true } else { are_refutable(cx, pats.iter().map(|pat| &**pat)) } - } + }, PatKind::Slice(ref head, ref middle, ref tail) => { are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) - } + }, } } @@ -793,3 +870,29 @@ pub fn remove_blocks(expr: &Expr) -> &Expr { expr } } + +pub fn opt_def_id(def: Def) -> Option { + match def { + Def::Fn(id) | + Def::Mod(id) | + Def::Static(id, _) | + Def::Variant(id) | + Def::VariantCtor(id, ..) | + Def::Enum(id) | + Def::TyAlias(id) | + Def::AssociatedTy(id) | + Def::TyParam(id) | + Def::Struct(id) | + Def::StructCtor(id, ..) | + Def::Union(id) | + Def::Trait(id) | + Def::Method(id) | + Def::Const(id) | + Def::AssociatedConst(id) | + Def::Local(id) | + Def::Upvar(id, ..) | + Def::Macro(id) => Some(id), + + Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None, + } +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index eefc2e5193a0..402985613aeb 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -12,7 +12,7 @@ pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"]; pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"]; pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"]; -pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"]; +pub const CSTRING_NEW: [&'static str; 5] = ["std", "ffi", "c_str", "CString", "new"]; pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Debug", "fmt"]; pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"]; pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Display", "fmt"]; @@ -64,6 +64,7 @@ pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; pub const RESULT_ERR: [&'static str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_OK: [&'static str; 4] = ["core", "result", "Result", "Ok"]; pub const SERDE_DE_VISITOR: [&'static str; 3] = ["serde", "de", "Visitor"]; +pub const SLICE_INTO_VEC: [&'static str; 4] = ["collections", "slice", "", "into_vec"]; pub const STRING: [&'static str; 3] = ["collections", "string", "String"]; pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 1dc2629d2077..e4938f1c1edc 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -29,9 +29,9 @@ pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1")); impl<'a> Display for Sugg<'a> { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { match *self { - Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => { - s.fmt(f) - } + Sugg::NonParen(ref s) | + Sugg::MaybeParen(ref s) | + Sugg::BinOp(_, ref s) => s.fmt(f), } } } @@ -168,10 +168,12 @@ impl<'a> Sugg<'a> { match self { Sugg::NonParen(..) => self, // (x) and (x).y() both don't need additional parens - Sugg::MaybeParen(sugg) => if sugg.starts_with('(') && sugg.ends_with(')') { - Sugg::MaybeParen(sugg) - } else { - Sugg::NonParen(format!("({})", sugg).into()) + Sugg::MaybeParen(sugg) => { + if sugg.starts_with('(') && sugg.ends_with(')') { + Sugg::MaybeParen(sugg) + } else { + Sugg::NonParen(format!("({})", sugg).into()) + } }, Sugg::BinOp(_, sugg) => Sugg::NonParen(format!("({})", sugg).into()), } @@ -247,18 +249,17 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { /// Whether the operator is a arithmetic operator (`+`, `-`, `*`, `/`, `%`). fn is_arith(op: &AssocOp) -> bool { - matches!(*op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus) + matches!(*op, + AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus) } /// Whether the operator `op` needs parenthesis with the operator `other` in the direction /// `dir`. fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { other.precedence() < op.precedence() || - (other.precedence() == op.precedence() && - ((op != other && associativity(op) != dir) || - (op == other && associativity(op) != Associativity::Both))) || - is_shift(op) && is_arith(other) || - is_shift(other) && is_arith(op) + (other.precedence() == op.precedence() && + ((op != other && associativity(op) != dir) || (op == other && associativity(op) != Associativity::Both))) || + is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op) } let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs { @@ -276,24 +277,12 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { let lhs = ParenHelper::new(lhs_paren, lhs); let rhs = ParenHelper::new(rhs_paren, rhs); let sugg = match op { - AssocOp::Add | - AssocOp::BitAnd | - AssocOp::BitOr | - AssocOp::BitXor | - AssocOp::Divide | - AssocOp::Equal | - AssocOp::Greater | - AssocOp::GreaterEqual | - AssocOp::LAnd | - AssocOp::LOr | - AssocOp::Less | - AssocOp::LessEqual | - AssocOp::Modulus | - AssocOp::Multiply | - AssocOp::NotEqual | - AssocOp::ShiftLeft | - AssocOp::ShiftRight | - AssocOp::Subtract => format!("{} {} {}", lhs, op.to_ast_binop().expect("Those are AST ops").to_string(), rhs), + AssocOp::Add | AssocOp::BitAnd | AssocOp::BitOr | AssocOp::BitXor | AssocOp::Divide | AssocOp::Equal | + AssocOp::Greater | AssocOp::GreaterEqual | AssocOp::LAnd | AssocOp::LOr | AssocOp::Less | + AssocOp::LessEqual | AssocOp::Modulus | AssocOp::Multiply | AssocOp::NotEqual | AssocOp::ShiftLeft | + AssocOp::ShiftRight | AssocOp::Subtract => { + format!("{} {} {}", lhs, op.to_ast_binop().expect("Those are AST ops").to_string(), rhs) + }, AssocOp::Inplace => format!("in ({}) {}", lhs, rhs), AssocOp::Assign => format!("{} = {}", lhs, rhs), AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, binop_to_string(op), rhs), @@ -335,11 +324,10 @@ fn associativity(op: &AssocOp) -> Associativity { match *op { Inplace | Assign | AssignOp(_) => Associativity::Right, - Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | - As | Colon => Associativity::Both, - Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | - ShiftRight | Subtract => Associativity::Left, - DotDot | DotDotDot => Associativity::None + Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both, + Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight | + Subtract => Associativity::Left, + DotDot | DotDotDot => Associativity::None, } } @@ -384,7 +372,7 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { } /// Return the indentation before `span` if there are nothing but `[ \t]` before it on its line. -fn indentation(cx: &T, span: Span) -> Option { +fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option { let lo = cx.sess().codemap().lookup_char_pos(span.lo); if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) { if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { @@ -403,17 +391,17 @@ fn indentation(cx: &T, span: Span) -> Option { } /// Convenience extension trait for `DiagnosticBuilder`. -pub trait DiagnosticBuilderExt { +pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> { /// Suggests to add an attribute to an item. /// /// Correctly handles indentation of the attribute and item. /// /// # Example /// - /// ```rust + /// ```rust,ignore /// db.suggest_item_with_attr(cx, item, "#[derive(Default)]"); /// ``` - fn suggest_item_with_attr(&mut self, cx: &T, item: Span, msg: &str, attr: &D); + fn suggest_item_with_attr(&mut self, cx: &T, item: Span, msg: &str, attr: &D); /// Suggest to add an item before another. /// @@ -421,7 +409,7 @@ pub trait DiagnosticBuilderExt { /// /// # Example /// - /// ```rust + /// ```rust,ignore /// db.suggest_prepend_item(cx, item, /// "fn foo() { /// bar(); @@ -430,13 +418,10 @@ pub trait DiagnosticBuilderExt { fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str); } -impl<'a, 'b, T: LintContext> DiagnosticBuilderExt for rustc_errors::DiagnosticBuilder<'b> { - fn suggest_item_with_attr(&mut self, cx: &T, item: Span, msg: &str, attr: &D) { +impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> { + fn suggest_item_with_attr(&mut self, cx: &T, item: Span, msg: &str, attr: &D) { if let Some(indent) = indentation(cx, item) { - let span = Span { - hi: item.lo, - ..item - }; + let span = Span { hi: item.lo, ..item }; self.span_suggestion(span, msg, format!("{}\n{}", attr, indent)); } @@ -444,20 +429,19 @@ impl<'a, 'b, T: LintContext> DiagnosticBuilderExt for rustc_errors::Diagnosti fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str) { if let Some(indent) = indentation(cx, item) { - let span = Span { - hi: item.lo, - ..item - }; + let span = Span { hi: item.lo, ..item }; let mut first = true; - let new_item = new_item.lines().map(|l| { - if first { - first = false; - format!("{}\n", l) - } else { - format!("{}{}\n", indent, l) - } - }).collect::(); + let new_item = new_item.lines() + .map(|l| { + if first { + first = false; + format!("{}\n", l) + } else { + format!("{}{}\n", indent, l) + } + }) + .collect::(); self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent)); } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index f847c397da86..dd3d4d261d05 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -32,8 +32,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { // search for `&vec![_]` expressions where the adjusted type is `&[_]` if_let_chain!{[ let ty::TypeVariants::TyRef(_, ref ty) = cx.tcx.tables().expr_ty_adjusted(expr).sty, @@ -65,7 +65,7 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { } else { return; } - } + }, higher::VecArgs::Vec(args) => { if let Some(last) = args.iter().last() { let span = Span { @@ -78,7 +78,7 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { } else { "&[]".into() } - } + }, }; span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 64ec3e5eec70..daf0721af05a 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -27,8 +27,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { // check for instances of 0.0/0.0 if_let_chain! {[ let ExprBinary(ref op, ref left, ref right) = expr.node, diff --git a/rustfmt.toml b/rustfmt.toml index c0695c04126e..18d146d49173 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,8 @@ max_width = 120 ideal_width = 100 -fn_args_density = "Compressed" fn_call_width = 80 -fn_args_paren_newline = false \ No newline at end of file +match_block_trailing_comma = true +fn_args_layout = "Block" +closure_block_indent_threshold = 0 +fn_return_indent = "WithWhereClause" +wrap_comments = true diff --git a/src/lib.rs b/src/lib.rs index 1b9333d80b09..9672f16eddc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![feature(plugin_registrar)] #![feature(rustc_private)] #![allow(unknown_lints)] -#![feature(borrow_state)] #![allow(missing_docs_in_private_items)] extern crate rustc_plugin; @@ -12,11 +11,14 @@ extern crate clippy_lints; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - if reg.sess.lint_store.borrow_state() == std::cell::BorrowState::Unused && reg.sess.lint_store.borrow().get_lint_groups().iter().any(|&(s, _, _)| s == "clippy") { - reg.sess.struct_warn("running cargo clippy on a crate that also imports the clippy plugin").emit(); - } else { - clippy_lints::register_plugins(reg); + if let Ok(lint_store) = reg.sess.lint_store.try_borrow() { + if lint_store.get_lint_groups().iter().any(|&(s, _, _)| s == "clippy") { + reg.sess.struct_warn("running cargo clippy on a crate that also imports the clippy plugin").emit(); + return; + } } + + clippy_lints::register_plugins(reg); } // only exists to let the dogfood integration test works. diff --git a/src/main.rs b/src/main.rs index a839bbad3417..0b91c79d21bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,32 +38,35 @@ impl ClippyCompilerCalls { } impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { - fn early_callback(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType) - -> Compilation { + fn early_callback( + &mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + descriptions: &rustc_errors::registry::Registry, + output: ErrorOutputType + ) -> Compilation { self.default.early_callback(matches, sopts, cfg, descriptions, output) } - fn no_input(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry) - -> Option<(Input, Option)> { + fn no_input( + &mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + odir: &Option, + ofile: &Option, + descriptions: &rustc_errors::registry::Registry + ) -> Option<(Input, Option)> { self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } - fn late_callback(&mut self, - matches: &getopts::Matches, - sess: &Session, - input: &Input, - odir: &Option, - ofile: &Option) - -> Compilation { + fn late_callback( + &mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option, + ofile: &Option + ) -> Compilation { self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { @@ -73,7 +76,12 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { let old = std::mem::replace(&mut control.after_parse.callback, box |_| {}); control.after_parse.callback = Box::new(move |state| { { - let mut registry = rustc_plugin::registry::Registry::new(state.session, state.krate.as_ref().expect("at this compilation stage the krate must be parsed").span); + let mut registry = rustc_plugin::registry::Registry::new(state.session, + state.krate + .as_ref() + .expect("at this compilation stage \ + the krate must be parsed") + .span); registry.args_hidden = Some(Vec::new()); clippy_lints::register_plugins(&mut registry); @@ -153,7 +161,7 @@ pub fn main() { if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { panic!("yummy"); } - + // Check for version and help flags even when invoked as 'cargo-clippy' if std::env::args().any(|a| a == "--help" || a == "-h") { show_help(); @@ -184,14 +192,16 @@ pub fn main() { let current_dir = std::env::current_dir(); - let package_index = metadata.packages.iter() + let package_index = metadata.packages + .iter() .position(|package| { let package_manifest_path = Path::new(&package.manifest_path); if let Some(ref manifest_path) = manifest_path { package_manifest_path == manifest_path } else { let current_dir = current_dir.as_ref().expect("could not read current directory"); - let package_manifest_directory = package_manifest_path.parent().expect("could not find parent directory of package manifest"); + let package_manifest_directory = package_manifest_path.parent() + .expect("could not find parent directory of package manifest"); package_manifest_directory == current_dir } }) @@ -205,7 +215,8 @@ pub fn main() { std::process::exit(code); } } else if ["bin", "example", "test", "bench"].contains(&&**first) { - if let Err(code) = process(vec![format!("--{}", first), target.name].into_iter().chain(args), &dep_path) { + if let Err(code) = process(vec![format!("--{}", first), target.name].into_iter().chain(args), + &dep_path) { std::process::exit(code); } } @@ -285,8 +296,10 @@ fn process(old_args: I, dep_path: P) -> Result<(), i32> let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC", path) - .spawn().expect("could not run cargo") - .wait().expect("failed to wait for cargo?"); + .spawn() + .expect("could not run cargo") + .wait() + .expect("failed to wait for cargo?"); if exit_status.success() { Ok(()) diff --git a/tests/compile-fail/absurd-extreme-comparisons.rs b/tests/compile-fail/absurd-extreme-comparisons.rs index 627cd888aac1..81cb658df8de 100644 --- a/tests/compile-fail/absurd-extreme-comparisons.rs +++ b/tests/compile-fail/absurd-extreme-comparisons.rs @@ -9,7 +9,7 @@ fn main() { let u: u32 = 42; u <= 0; - //~^ ERROR this comparison involving the minimum or maximum element for this type contains a case that is always true or always false + //~^ ERROR this comparison involving the minimum or maximum element for this type contains a //~| HELP using u == 0 instead u <= Z; //~^ ERROR this comparison involving @@ -41,10 +41,10 @@ fn main() { //~| HELP because 1-1 is the minimum value for this type, this comparison is always false u >= !0; //~^ ERROR this comparison involving - //~| HELP because !0 is the maximum value for this type, the case where the two sides are not equal never occurs, consider using u == !0 instead + //~| HELP consider using u == !0 instead u <= 12 - 2*6; //~^ ERROR this comparison involving - //~| HELP because 12 - 2*6 is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == 12 - 2*6 instead + //~| HELP consider using u == 12 - 2*6 instead let i: i8 = 0; i < -127 - 1; diff --git a/tests/compile-fail/assign_ops2.rs b/tests/compile-fail/assign_ops2.rs index 1537232bf182..e8549c01bc93 100644 --- a/tests/compile-fail/assign_ops2.rs +++ b/tests/compile-fail/assign_ops2.rs @@ -34,3 +34,24 @@ fn main() { a %= 42 % a; a <<= 6 << a; } + +// check that we don't lint on op assign impls, because that's just the way to impl them + +use std::ops::{Mul, MulAssign}; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Wrap(i64); + +impl Mul for Wrap { + type Output = Self; + + fn mul(self, rhs: i64) -> Self { + Wrap(self.0 * rhs) + } +} + +impl MulAssign for Wrap { + fn mul_assign(&mut self, rhs: i64) { + *self = *self * rhs + } +} diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index 43216754f753..090c39abc926 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -21,13 +21,13 @@ macro_rules! blocky_too { fn macro_if() { if blocky!() { } - + if blocky_too!() { } } fn condition_has_block() -> i32 { - if { //~ERROR in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let' + if { //~ERROR in an 'if' condition, avoid complex blocks or closures with blocks; let x = 3; x == 3 } { @@ -55,12 +55,12 @@ fn pred_test() { // this is a sneaky case, where the block isn't directly in the condition, but is actually // inside a closure that the condition is using. same principle applies. add some extra // expressions to make sure linter isn't confused by them. - if v == 3 && sky == "blue" && predicate(|x| { let target = 3; x == target }, v) { //~ERROR in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let' - + if v == 3 && sky == "blue" && predicate(|x| { let target = 3; x == target }, v) { + //~^ERROR in an 'if' condition, avoid complex blocks or closures with blocks; } - if predicate(|x| { let target = 3; x == target }, v) { //~ERROR in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let' - + if predicate(|x| { let target = 3; x == target }, v) { + //~^ERROR in an 'if' condition, avoid complex blocks or closures with blocks; } } diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 3e65d1aeec47..9b1e1ec801ec 100644 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -9,6 +9,7 @@ #![allow(blacklisted_name)] #![allow(collapsible_if)] #![allow(zero_divided_by_zero, eq_op)] +#![allow(path_statements)] fn bar(_: T) {} fn foo() -> bool { unimplemented!() } @@ -236,6 +237,13 @@ fn if_same_then_else() -> Result<&'static str, ()> { if let Some(42) = None {} } + if true { + if let Some(42) = None:: {} + } + else { + if let Some(42) = None:: {} + } + if true { if let Some(a) = Some(42) {} } diff --git a/tests/compile-fail/dlist.rs b/tests/compile-fail/dlist.rs index e79196191212..63c678eb69c2 100644 --- a/tests/compile-fail/dlist.rs +++ b/tests/compile-fail/dlist.rs @@ -1,12 +1,37 @@ #![feature(plugin, collections)] +#![feature(associated_type_defaults)] +#![feature(associated_consts)] #![plugin(clippy)] #![deny(clippy)] +#![allow(dead_code)] extern crate collections; use collections::linked_list::LinkedList; -pub fn test(_: LinkedList) { //~ ERROR I see you're using a LinkedList! +trait Foo { + type Baz = LinkedList; //~ ERROR I see you're using a LinkedList! + fn foo(LinkedList); //~ ERROR I see you're using a LinkedList! + const BAR : Option>; //~ ERROR I see you're using a LinkedList! +} + +// ok, we don’t want to warn for implementations, see #605 +impl Foo for LinkedList { + fn foo(_: LinkedList) {} + const BAR : Option> = None; +} + +struct Bar; +impl Bar { + fn foo(_: LinkedList) {} //~ ERROR I see you're using a LinkedList! +} + +pub fn test(my_favourite_linked_list: LinkedList) { //~ ERROR I see you're using a LinkedList! + println!("{:?}", my_favourite_linked_list) +} + +pub fn test_ret() -> Option> { //~ ERROR I see you're using a LinkedList! + unimplemented!(); } fn main(){ diff --git a/tests/compile-fail/enum_variants.rs b/tests/compile-fail/enum_variants.rs index f0fda37f7f8f..585535f9d999 100644 --- a/tests/compile-fail/enum_variants.rs +++ b/tests/compile-fail/enum_variants.rs @@ -1,6 +1,6 @@ #![feature(plugin, non_ascii_idents)] #![plugin(clippy)] -#![deny(clippy)] +#![deny(clippy, pub_enum_variant_names)] enum FakeCallType { CALL, CREATE @@ -87,4 +87,19 @@ enum NonCaps { //~ ERROR: All variants have the same prefix: `Prefix` PrefixCake, } +pub enum PubSeall { //~ ERROR: All variants have the same prefix: + WithOutCake, + WithOutTea, + WithOut, +} + +#[allow(pub_enum_variant_names)] +mod allowed { + pub enum PubAllowed { + SomeThis, + SomeThat, + SomeOtherWhat, + } +} + fn main() {} diff --git a/tests/compile-fail/formatting.rs b/tests/compile-fail/formatting.rs index 9b8146dc2293..faaae46af718 100644 --- a/tests/compile-fail/formatting.rs +++ b/tests/compile-fail/formatting.rs @@ -5,6 +5,7 @@ #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(if_same_then_else)] +#![allow(deref_addrof)] fn foo() -> bool { true } diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index 6616f7bdc86c..30a66a715f20 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -4,6 +4,7 @@ #![deny(no_effect, unnecessary_operation)] #![allow(dead_code)] #![allow(path_statements)] +#![allow(deref_addrof)] #![feature(untagged_unions)] struct Unit; diff --git a/tests/compile-fail/reference.rs b/tests/compile-fail/reference.rs new file mode 100644 index 000000000000..b77afbc12702 --- /dev/null +++ b/tests/compile-fail/reference.rs @@ -0,0 +1,88 @@ +#![feature(plugin)] +#![plugin(clippy)] + +fn get_number() -> usize { + 10 +} + +fn get_reference(n : &usize) -> &usize { + n +} + +#[allow(many_single_char_names)] +#[allow(unused_variables)] +#[deny(deref_addrof)] +fn main() { + let a = 10; + let aref = &a; + + let b = *&a; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = a; + + let b = *&get_number(); + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = get_number(); + + let b = *get_reference(&a); + + let bytes : Vec = vec![1, 2, 3, 4]; + let b = *&bytes[1..2][0]; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = bytes[1..2][0]; + + //This produces a suggestion of 'let b = (a);' which + //will trigger the 'unused_parens' lint + let b = *&(a); + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = (a) + + let b = *(&a); + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = a; + + let b = *((&a)); + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = a + + let b = *&&a; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = &a; + + let b = **&aref; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = *aref; + + //This produces a suggestion of 'let b = *&a;' which + //will trigger the 'deref_addrof' lint again + let b = **&&a; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let b = *&a; + + { + let mut x = 10; + let y = *&mut x; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let y = x; + } + + { + //This produces a suggestion of 'let y = *&mut x' which + //will trigger the 'deref_addrof' lint again + let mut x = 10; + let y = **&mut &mut x; + //~^ERROR immediately dereferencing a reference + //~|HELP try this + //~|SUGGESTION let y = *&mut x; + } +} diff --git a/tests/ice_exacte_size.rs b/tests/ice_exacte_size.rs index 37e3b4ebe7a9..eeab3a2bec59 100644 --- a/tests/ice_exacte_size.rs +++ b/tests/ice_exacte_size.rs @@ -14,4 +14,4 @@ impl Iterator for Foo { } } -impl ExactSizeIterator for Foo { } +impl ExactSizeIterator for Foo {} diff --git a/tests/issue-825.rs b/tests/issue-825.rs index 76b0250ca0e1..87cbb72f5857 100644 --- a/tests/issue-825.rs +++ b/tests/issue-825.rs @@ -5,19 +5,10 @@ // this should compile in a reasonable amount of time fn rust_type_id(name: String) { - if "bool" == &name[..] || - "uint" == &name[..] || - "u8" == &name[..] || - "u16" == &name[..] || - "u32" == &name[..] || - "f32" == &name[..] || - "f64" == &name[..] || - "i8" == &name[..] || - "i16" == &name[..] || - "i32" == &name[..] || - "i64" == &name[..] || - "Self" == &name[..] || - "str" == &name[..] { + if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || + "u32" == &name[..] || "f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || + "i16" == &name[..] || "i32" == &name[..] || "i64" == &name[..] || + "Self" == &name[..] || "str" == &name[..] { unreachable!(); } } diff --git a/tests/trim_multiline.rs b/tests/trim_multiline.rs index 90f1c76fb80e..d6de36bfca73 100644 --- a/tests/trim_multiline.rs +++ b/tests/trim_multiline.rs @@ -13,6 +13,7 @@ fn test_single_line() { } #[test] +#[cfg_attr(rustfmt, rustfmt_skip)] fn test_block() { assert_eq!("\ if x { @@ -37,6 +38,7 @@ if x { } #[test] +#[cfg_attr(rustfmt, rustfmt_skip)] fn test_empty_line() { assert_eq!("\ if x { diff --git a/util/update_lints.py b/util/update_lints.py index 965d7e272c5b..ddb5d3ab32fd 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -98,7 +98,10 @@ def gen_deprecated(lints): """Declare deprecated lints""" for lint in lints: - yield ' store.register_removed("%s", "%s");\n' % (lint[1], lint[2]) + yield ' store.register_removed(\n' + yield ' "%s",\n' % lint[1] + yield ' "%s",\n' % lint[2] + yield ' );\n' def replace_region(fn, region_start, region_end, callback,